多线程Thread的用法


1.线程的用法

无参数的线程: 

 1         private void button1_Click(object sender, EventArgs e)
 2         {
 3             Thread thread1 = new Thread(new ThreadStart(fun));
 4             thread1.Start();
 5         }
 6 
 7         private void fun()
 8         {
 9             int a = 0;
10             for (int i = 0; i < 999999999; i++)
11             {
12                 a = i;
13             }
14             MessageBox.Show(a.ToString());
15         }     

带参数的线程:

第一种方法:使用ParameterizedThreadStart

 1        private void button2_Click(object sender, EventArgs e)
 2         {
 3             Thread thread1 = new Thread(new ParameterizedThreadStart(fun1));
 4             //Thread thread1 = new Thread(fun1);//这样写也可以
 5             thread1.Start("123");
 6 
 7             List<string> list = new List<string> { "张三", "李四", "王五" };
 8             Thread thread2 = new Thread(new ParameterizedThreadStart(fun2));
 9             thread2.Start(list);
10         }
11 
12        private void fun1(object obj)
13         {
14             //注意参数必须为object类型
15             MessageBox.Show(obj.ToString());
16         }
17 
18         private void fun2(object obj)
19         {
20             List<string> list = obj as List<string>;
21             for (int i = 0; i < list.Count; i++)
22             {
23                 MessageBox.Show(list[i]);
24             }
25         }

第二种方法:将线程执行的方法和参数都封装到一个类里面。通过实例化该类,方法就可以调用属性来实现间接的类型安全地传递参数。

 1         private void button3_Click(object sender, EventArgs e)
 2         {
 3             NewThread newThread = new NewThread("张三");//实例化对象
 4             Thread thread = new Thread(new ThreadStart(newThread.fun));
 5             thread.Start();
 6 
 7             List<string> list = new List<string> { "张三", "李四", "王五" };
 8             Thread thread2 = new Thread(new ParameterizedThreadStart(newThread.fun1));
 9             thread2.Start(list);
10         }
 1     public class NewThread
 2     {
 3         private string name;
 4         public NewThread(string name)
 5         {
 6             this.name = name;
 7         }
 8         public void fun()
 9         {
10             MessageBox.Show(string.Format("我的名字叫{0}", name));
11         }
12         public void fun1(object obj)
13         {
14             List<string> list = obj as List<string>;
15             for (int i = 0; i < list.Count; i++)
16             {
17                 MessageBox.Show(list[i]);
18             }
19         }
20     }

2.IsBackground:获取一个值,是否为后台线程。true为后台线程,false为前台线程,默认为前台线程。

前台线程和后台线程的区别:前台线程是应用程序必须运行完所有线程才可以退出。后台的则直接退出。

 1         private void button1_Click(object sender, EventArgs e)
 2         {
 3             Thread thread1 = new Thread(new ThreadStart(fun));
 4             thread1.IsBackground = true;//后台线程
 5             thread1.Start();
 6         }
 7         private void fun()
 8         {
 9             int a = 0;
10             for (int i = 0; i < 999999999; i++)
11             {
12                 a = i;
13             }
14             MessageBox.Show(a.ToString());
15         }

运行结果:当你关闭button1后立即关闭窗口,则整个程序退出,就不会弹窗了。

如果不设置thread1.IsBackground或者设置为false,当你关闭窗口后,应用程序应在执行,结果还会弹窗。

3.CheckForIllegalCrossThreadCalls和Invoke或BeginInvoke的用法

这种异常的解决办法:

第一种:CheckForIllegalCrossThreadCalls=false;不对它进行线程检查(这种方法虽然简单,但不提倡用)

 1  public partial class Form1 : Form
 2     {
 3         public Form1()
 4         {
 5             InitializeComponent();
 6             TextBox.CheckForIllegalCrossThreadCalls = false;//是否对该控件进行线程检查。
 7         }
 8 
 9         private void button1_Click(object sender, EventArgs e)
10         {
11             Thread thread1 = new Thread(new ThreadStart(fun));
12             thread1.IsBackground = true;
13             thread1.Start();
14         }
15       
16         private void fun()
17         {
18             for (int i = 0; i < 2000; i++)
19             {
20                 int a = Convert.ToInt32(textBox1.Text);
21                 a++;
22                 textBox1.Text = a.ToString();
23             }            
24         }     
25     }

第二种:Invoke和BeginInvoke

Control.Invoke 方法 (Delegate) :在拥有此控件的基础窗口句柄的线程上执行指定的委托(是同步执行的,会阻塞当前线程,只允许单线程修改)。
Control.BeginInvoke 方法 (Delegate) :在创建控件的基础句柄所在线程上异步执行指定委托(会启用线程池,是异步的不会阻塞线程)。

 1         private void button1_Click(object sender, EventArgs e)
 2         {
 3             Thread thread3 = new Thread(new ThreadStart(doWork));
 4             thread3.IsBackground = true;
 5             thread3.Start();
 6         }
 7         public delegate void MyInvoke();
 8         public void doWork()
 9         {
10             MyInvoke callBack = new MyInvoke(fun3);
11             //this.BeginInvoke(callBack);
12             this.Invoke(callBack);
13         }
14         private void fun3()
15         {
16             for (int i = 0; i < 2000; i++)
17             {
18                 int a = Convert.ToInt32(textBox1.Text);
19                 a++;
20                 textBox1.Text = a.ToString();
21             }
22         }

4.lock的用法

textBox1.Text的初始值为textBox1.Text="0";
大家猜下当点击Button时这个textBox1.Text的值会是多少呢?
 1         public Form1()
 2         {
 3             InitializeComponent();
 4             TextBox.CheckForIllegalCrossThreadCalls = false;//是否对盖控件进行线程的调用。
 5         }
 6 
 7         private void button1_Click(object sender, EventArgs e)
 8         {
 9             Thread thread1 = new Thread(new ThreadStart(fun));
10             thread1.IsBackground = true;
11             thread1.Start();
12 
13             Thread thread2 = new Thread(new ThreadStart(fun));
14             thread2.IsBackground = true;
15             thread2.Start();
16         }
17 
18         private void fun()
19         {         
20             for (int i = 0; i < 2000; i++)
21             {
22                 int a = Convert.ToInt32(textBox1.Text);
23                 a++;
24                 textBox1.Text = a.ToString();
25             }
26         }

结果:

为什么会是一个随机的数呢?而不是2000或者4000?

因为当你在点击Button时,先开启thread1然后再开启thread2,但是都在执行着那个方法。在开启thread2的时候,文本框内的值可能不是thread2线程上次的值。

例如:thread1在某次执行时,文本框里的值为1000,thread2上次执行的结果为999,它在这次执行时就有可能取thread1执行后的值1000来计算。这时文本框就为1001了。

所以整个下来,就会产生一个随机的数字了。

解决办法:

 1         private void fun()
 2         {
 3             lock (this)
 4             {
 5                 for (int i = 0; i < 2000; i++)
 6                 {
 7                     int a = Convert.ToInt32(textBox1.Text);
 8                     a++;
 9                     textBox1.Text = a.ToString();
10                 }
11             }
12         }

就是在方法中加上一个lock锁。当thread1在执行时,不让thread2执行这个循环。

最后的结果就是


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM