线程
线程应用场景:
(1):希望获得更多操作系统资源尽快处理我们的业务,缩短处理的时间
(2) 如果一个非常复杂的操作.需要占用非常长的时间,而WinFrom又不允许阻塞UI线程
后台线程
创建线程
1 private void button2_Click(object sender, EventArgs e) 2 { 3 //创建一个委托指向其中一个方法 4 ThreadStart threadStart = new ThreadStart(StartCaul); 5 //创建线程 6 Thread myThread = new Thread(threadStart);//可以直接放方法名进去 StartCaul 7 //开启线程 8 myThread.Start(); 9 //设置线程的优先级 10 myThread.Priority = ThreadPriority.Normal;//建议操作系统将创建的线程优先级设置为最高。 11 //可以给线程起个名字 12 myThread.Name = "myThreadBB"; 13 //终止线程 14 myThread.Abort(); 15 //阻塞主线程执行 16 myThread.Join(1000); 17 //设置后台线程 18 myThread.IsBackground = true; 19 20 }
控制线程结束
1 bool isStop = false; 2 private void StartCaul() 3 { 4 int a = 0; 5 for (int i = 0; i < 600000000; i++) 6 { 7 if (!isStop) 8 { 9 a = i; 10 } 11 else 12 { 13 14 } 15 } 16 //MessageBox.Show(a.ToString()); 17 this.textBox1.Text = a.ToString(); 18 }
微软提供跨线程检测 不建议把他用一下方法取消
TextBox.CheckForIllegalCrossThreadCalls = false;
跨线程访问
1 /// <summary> 2 /// 完美的跨线程访问 要访问主线程创建的TextBox 需设置跨线程访问 3 /// </summary> 4 /// <param name="sender"></param> 5 /// <param name="e"></param> 6 private void button4_Click(object sender, EventArgs e) 7 { 8 //创建一个线程 9 Thread thread1 = new Thread(ShowResult); 10 //设置为后台线程 11 thread1.IsBackground = true; 12 thread1.Start(); 13 } 14 private void ShowResult() 15 { 16 int a = 0; 17 for (int i = 0; i < 600000000; i++) 18 { 19 20 a = i; 21 22 } 23 //现在就是对文本框进行跨线程访问 返回是true 24 if (this.textBox1.InvokeRequired)//是否要对文本框进行跨线程访问。 25 { 26 //Invoke:去找创建TextBox的线程(主线程(UI线程)),由主线程完成委托方法的调用。 27 //后面2个参数给方法传值 28 //泛型约束<TextBox, string> 29 this.textBox1.Invoke(new Action<TextBox, string>(ShowTextBoxValue), this.textBox1, a.ToString());// 30 } 31 else 32 { 33 this.textBox1.Text = a.ToString(); 34 } 35 } 36 //给文本框赋值函数 不需要返回值 37 private void ShowTextBoxValue(TextBox txt,string value) 38 { 39 txt.Text = value; 40 41 }
线程执行带参数的方法
1 private void button3_Click(object sender, EventArgs e) 2 { 3 //创建一个List集合 4 List<int> list = new List<int>() {1,2,3,4,5 }; 5 //传一个方法 6 ParameterizedThreadStart parThreadStart = new ParameterizedThreadStart(Show); 7 Thread thread1 = new Thread(parThreadStart); 8 //标记为后台线程 9 thread1.IsBackground = true; 10 //Start方法有2个参数 向方法传递参数 11 thread1.Start(list); 12 } 13 private void Show(object obj) 14 { 15 //遍历list集合输出 16 List<int> list = obj as List<int>; 17 foreach (int i in list) 18 { 19 MessageBox.Show(i.ToString()); 20 } 21 }
多线程同步
当多个线程访问同一资源时要加锁,多用户并发问题.加锁可以解决多线程访问同一资源问题,但是它带来的问题比较慢
1 //开启2个线程调同一个方法 当多个线程访问同一资源时要加锁 2 3 private void button5_Click(object sender, EventArgs e) 4 { 5 // this.textBox1.Text = "safasdfd"; 6 Thread thread1 = new Thread(AddSum); 7 thread1.IsBackground = true; 8 thread1.Start(); 9 10 Thread thread2 = new Thread(AddSum); 11 thread2.IsBackground = true; 12 thread2.Start(); 13 } 14 //锁 15 private static readonly object obj = new object(); 16 17 private void AddSum() 18 { 19 lock (obj) 20 { 21 22 for (int i = 0; i < 2000; i++) 23 { 24 int a = Convert.ToInt32(this.textBox1.Text); 25 a++; 26 this.textBox1.Text = a.ToString(); 27 } 28 } 29 30 }
浏览器对服务器发送请求,等于开启了一个线程,线程本身是消耗资源的,一台web服务器挺不住太多线程,CPU来回切换消耗资源
lock 是一个语法糖 实际写法Monitor.Enter(obj)
线程池
1 什么时候用线程池? 什么时候手动创建线程? 2 1,能用线程池的就用线程池 3 4 2.我们想手动关闭线程的话那么必须手动创建 Abort() Join() 5 6 3.我们需要对线程池的线程的优先级做设置的情景下,只能使用手动创建线程 7 8 4.如果执行的线程执行时间特别长,建议手动创建线程. 9 10 线程池:提高了线程的利用率,非常适合工作任务比较小,而且又需要使用单独的线程来解决的问题. 11 12 线程切换消耗资源,cpu在切换线程的时候,需要把当前线程执行的状态保持到寄存器里面去. 13 14 线程创建非常消耗资源.线程创建非常慢,占用大量的内存空间,每个线程最少1M内存开销.
1 Stopwatch sw =new Stopwatch(); 2 sw.Start(); 3 for (int i = 0; i < 1000; i++) 4 { 5 new Thread(() => 6 { 7 int i2 = 1 + 1; 8 9 }).Start(); 10 } 11 sw.Stop(); 12 Console.WriteLine(sw.Elapsed.TotalMilliseconds); 13 14 //重新开始计时 15 sw.Reset(); 16 sw.Restart(); 17 for (int i = 0; i < 1000; i++) 18 { 19 //从线程池取出一个线程 20 ThreadPool.QueueUserWorkItem(new WaitCallback(PoolCallBack), "sssss"+i); 21 //ThreadPool.GetMaxThreads 22 } 23 sw.Stop(); 24 Console.WriteLine(sw.Elapsed.TotalMilliseconds); 25 26 Console.ReadKey(); 27 28 } 29 private static void PoolCallBack(object state) 30 { 31 int i = 1 + 1; 32 33 }