1.首先讲解一下什么是线程(该定义是参考线程的百度百科)
线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组成。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。一个线程可以创建和撤消另一个线程,同一进程中的多个线程之间可以并发执行。由于线程之间的相互制约,致使线程在运行中呈现出间断性。线程也有就绪、阻塞和运行三种基本状态。每一个程序都至少有一个线程,若程序只有一个线程,那就是程序本身。线程是程序中一个单一的顺序控制流程。在单个程序中同时运行多个线程完成不同的工作,称为多线程。
2.为什么要用多线程?
让计算机“同时”做多个事情,节约时间;后台运行程序,提高程序的运行效率,也不会使主界面出现无响应的情况;多线程可以让一个程序“同时”处理多个事情;计算机CPU大部分时间处于空闲状态,浪费了大量的CPU资源。
一个进程至少有一个默认的线程为主线程。
下面写一个程序来说明单线程带来的问题。新建一个window窗体(该进程的UI线程为主线程),在窗体上拖一个button控件,添加该button的双击事件,写如下代码:
1 //单线程的缺点
2 private void button1_Click(object sender, EventArgs e)
3 {
4 DateTime beginTime = DateTime.Now;
5 for (int i = 0; i < 999999999; i++)
6 { }
7 TimeSpan ts = beginTime.Subtract(DateTime.Now);
8
9 MessageBox.Show("循环执行完毕)" + ts.TotalMilliseconds);
10 }
运行该程序,可以发现当点击了button按钮以后,window窗体不可以移动,只有弹出“循环执行完毕”之后窗体才可以被移动。这就是单线程的缺点,CUP让UI线程执行单击事件引发的程序,不能在执行UI线程本来做的事情,这就好比一个前台服务员本来该接待客户,但是她去忙别的事情了,导致她不能接待客户了。即她不能一边接待客户一边去忙别的事情。
为了解决这个问题,引入了多线程的概念,现在写一个程序来说明利用多线程是如何解决上述程序的问题的。在上面新建的窗体上再拖一个button,添加该button的双颊事件,写如下代码:
1 void CountTimes()
2 {
3 DateTime beginTime = DateTime.Now;
4 for (int i = 0; i < 999999999; i++)
5 { }
6 TimeSpan ts = beginTime.Subtract(DateTime.Now);
7
8 MessageBox.Show("循环执行完毕)" + ts.TotalMilliseconds);
9 }
10 //使用多线程来解决UI卡死问题
11 private void button2_Click(object sender, EventArgs e)
12 {
13 //创建线程对象 传入 委托线程执行的方法
14 Thread ts = new Thread(CountTimes);
15 //启动线程 执行方法
16 ts.Start();
17 //将线程设置为后台线程(当所有的前台线程结束后,后台线程会自动退出)
18 //ts.IsBackground = true;//将该线程设置为后台线程
19 }
3. .net中如何实现多线程1
线程肯定也是要执行一段代码的,所以要产生一个线程,必须先为该线程写一个方法,这个方法中的代码就是该线程运行所要执行的代码(找个人来做一件事情);线程启动时 ,通过委托调用该方法(线程启动时,调用传过来的委托,委托就会执行相应的方法,实现线程执行方法)
4. .net中如何实现多线程2
产生一个线程的4步骤:编写产生线程所要执行的方法;引用System.Threading命名空间;实例化Thread类,并传入一个指向线程所要运行方法的委托(这时候这个线程已经产生,但是还没有运行);调用Thread实例的Start方法,标记该线程可以被CUP执行了,但是具体执行时间由CUP决定。
5.前台线程:只有所有的前台线程都关闭才能完成程序关闭时;后台线程:只要所有的前台线程结束,后台线程自动结束。
6.方法重入问题:
新建一个window窗体,拖一个button控件和一个textbox控件,修改textbox控件的text属性值为0,添加该button按钮的双击事件,写如下代码:
1 void ChangeText() 2 { 3 for (int i = 0; i < 1000; i++) 4 { 5 int a = int.Parse(textBox1.Text); 6 Console.WriteLine(Thread.CurrentThread.Name+",a="+a+",i="+i); 7 a++; 8 textBox1.Text = a.ToString(); 9 } 10 } 11 //方法重入问题 12 private void button3_Click(object sender, EventArgs e) 13 { 14 Thread thread1 = new Thread(ChangeText); 15 thread1.Name = "t1"; 16 thread1.Start(); 17 18 }
运行该程序,系统会报错“线程间操作无效: 从不是创建控件“textBox1”的线程访问它。”这是因为创建textbox的线程不是咱们在button3_Click事件里边new的线程,线程之间是相互独立的。(对线程了解不是太多,自己的浅见)
1 public Form1() 2 { 3 InitializeComponent(); 4 TextBox.CheckForIllegalCrossThreadCalls = false;//关掉微软对错误线程的调用 5 }
通过写上一句代码,可以关掉微软对错误线程的调用。
1 void ChangeText() 2 { 3 for (int i = 0; i < 2000; i++) 4 { 5 int a = int.Parse(textBox1.Text); 6 Console.WriteLine(Thread.CurrentThread.Name+",a="+a+",i="+i); 7 a++; 8 textBox1.Text = a.ToString(); 9 } 10 } 11 //方法重入问题 12 private void button3_Click(object sender, EventArgs e) 13 { 14 Thread thread1 = new Thread(ChangeText); 15 thread1.Name = "t1"; 16 thread1.IsBackground = true;//将该线程设置为后台线程是为了防止用户在运行过程中关闭窗体而引发的错误 17 thread1.Start(); 18 19 20 Thread thread2 = new Thread(ChangeText); 21 thread2.Name = "t2"; 22 thread2.IsBackground = true; 23 thread2.Start(); 24 }
观察该程序的运行结果可以看出两个线程是相互独立的,两个线程在执行同一个方法时并不相互影响。