多線程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