多线程学习笔记《-》

1.进程:是操做系统结构的基础;是一个正在执行的程序;计算机中正在运行的程序实例;能够分配给处理器并由处理器执行的一个实体;由单一顺序的执行显示,一个当前状态和一组相关的系统资源所描述的活动单元。
2.线程:线程是程序中一个单一的顺序控制流程。是程序执行流的最小单元。另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程本身不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的所有资源。一个线程能够建立和撤消另外一个线程,同一进程中的多个线程之间能够并发执行。因为线程之间的相互制约,导致线程在运行中呈现出间断性。线程也有就绪、阻塞和运行三种基本状态。每个程序都至少有一个线程,若程序只有一个线程,那就是程序自己。

3.多线程:在单个程序中同时运行多个线程完成不一样的工做,称为多线程。
    web

小结:其实更容易理解一点进程与线程的话,能够举这样一个例子:把进程理解成为一个运营着的公司,然而每个公司员工就能够叫作一个进程。每一个公司至少要有一个员工,员工越多,若是你的管理合理的话,公司的运营速度就会越好。这里官味一点话就是说。cpu大部分时间处于空闲时间,浪费了cpu资源,多线程可让一个程序“同时”处理多个事情,提升效率。
     多线程

单线程问题演示
     并发

建立一个WinForm应用程序,这里出现的问题是,点击按钮后若是在弹出提示框以前,窗体是不能被拖动的。
函数

复制代码ui

  1. private void button1_Click(object sender, EventArgs e)this

  2.         {spa

  3.             for (int i = 0; i < 10000000000; i++)  操作系统

  4.             {线程

  5.                 i += 1;orm

  6.             }

  7.             MessageBox.Show("出现后能拖动,提示没出现以前窗体不能被拖动");

  8.         }


缘由:运行这个应用程序的时候,窗体应用程序自带一个叫作UI的线程,这个线程负责窗体界面的移动大小等。若是点击按钮则这个线程就去处理这个循环计算,而放弃了其它操做,故而窗体拖动无响应。这就是单线程带来的问题。
解决办法:使用多线程,咱们本身建立线程。把计算代码放入咱们本身写的线程中,UI线程就能继续作他的界面响应了。
    

线程的建立
    

线程的实现:线程必定是要执行一段代码的,因此要产生一个线程,必须先为该线程写一个方法,这个方法中的代码,就是该线程中要执行的代码,然而启动线程时,是经过委托调用该方法的。线程启动是,调用传过来的委托,委托就会执行相应的方法,从而实现线程执行方法。

复制代码

  1. //建立线程  

  2.         private void button1_Click(object sender, EventArgs e)

  3.         {

  4.             //ThreadStart是一个无参无返回值的委托。

  5.             ThreadStart ts = new ThreadStart(js);

  6.             //初始化Thread的新实例,并经过构造方法将委托ts作为参数赋初始值。

  7.             Thread td = new Thread(ts);   //须要引入System.Threading命名空间

  8.             //运行委托

  9.             td.Start();

  10.         }

  11.         //建立的线程要执行的函数。

  12.         void js()

  13.         {

  14.             for (int i = 0; i < 1000000000; i++)

  15.             {

  16.                 i += 1;

  17.             }

  18.             MessageBox.Show("提示出现先后窗体都能被拖动");

  19.         }


把这个计算写入本身写的线程中,就解决了单线程中的界面无反应缺陷。
    

小结:建立线程的4个步骤:1.编写线程索要执行的方法。2.引用System.Threading命名空。3.实例化Thread类,并传入一个指向线程所要运行方法的委托。4.调用Start()方法,将该线程标记为能够运行的状态,但具体执行时间由cpu决定。
    

方法重入(多个线程执行一个方法)
    

因为线程可与同属一个进程的其它线程共享进程所拥有的所有资源。
因此多个线程同时执行一个方法的状况是存在的,然而这里不通过处理的话会出现一点问题,线程之间前后争抢资源,导致数据计算结果错乱。 

复制代码

  1. public partial class 方法重入 : Form

  2.     {

  3.         public 方法重入()

  4.         {

  5.             InitializeComponent();

  6.  

  7.             //设置TextBox类的这个属性是由于,开启ui线程,

  8.             //微软设置检测不容许其它线程对ui线程的数据进行访问,这里咱们把检测关闭,也就容许了其它线程对ui线程数据的访问。

  9.             //若是检测不设置为False,则报错。

  10.             TextBox.CheckForIllegalCrossThreadCalls = false;

  11.         }

  12.  

  13.         private void button1_Click(object sender, EventArgs e)

  14.         {

  15.             textBox1.Text = "0";

  16.             //开启第一个线程,对js方法进行计算

  17.             ThreadStart ts = new ThreadStart(js);

  18.             Thread td = new Thread(ts);

  19.             td.Start();

  20.  

  21.             //开启第二个线程,对js方法进行计算

  22.             ThreadStart ts1 = new ThreadStart(js);

  23.             Thread td1 = new Thread(ts1);

  24.             td1.Start();

  25.         }

  26.         //多线程要重入的方法。

  27.         void js()

  28.         {

  29.             int a = Convert.ToInt32(textBox1.Text);

  30.             for (int i = 0; i < 2000; i++)

  31.             {

  32.                 a++;

  33.                 textBox1.Text = a.ToString();

  34.             }

  35.         }

  36.     }



出错现象:点击按钮后TextBox1中数据为2000+或2000,若是你看到的数据一直是2000说明你的计算机cpu比较牛X,这样的话你想看到不是2000的话,你能够多点击几回试试,真不行的话,代码中给TextBox1赋值为0,换作在界面中给textBox1数值默认值为0试试看。
出错缘由:两个进程同时计算这个方法,不相干扰应该每一个线程计算的结果都是2000的,可是这里的结果输出却让人之外,缘由是第一个两个线程同时计算,并非同时开始计算,而是根据cpu决定的哪一个先开始,哪一个后开始,虽然相差时间很少,但后开始的就会取用先开始计算过的数据计算,这样就会致使计算错乱。
解决办法:解决这个的一个简单办法解释给方法加锁,加锁的意思就是第一个线程取用过这个资源完毕后,第二个线程再来取用此资源。造成排队效果。
下面给方法加锁。

复制代码

  1. //多线程要重入的方法,这里加锁。

  2.         void js()

  3.         {

  4.             lock (this)

  5.             {

  6.                 int a = Convert.ToInt32(textBox1.Text);

  7.                 for (int i = 0; i < 2000; i++)

  8.                 {

  9.                     a++;

  10.                     textBox1.Text = a.ToString();

  11.                 }

  12.             }

  13.         }


给方法加过锁后,线程一前一后取用资源,就能避免不可预计的错乱结果,第一个线程计算为2000,第二个线程计算就是从2000开始,这里的结果就为4000。
    

小结:多线程能够同时运行,提升了cpu的效率,这里的同时并非同时开始,同时结束,他们的开始是由cpu决定的,时间相差不大,但会有不可预计的计算错乱,这里要注意相似上面例子致使的方法重入问题。
    

前台线程后台线程
    

.Net的公用语言运行时能区分两种不一样类型的线程:前台线程和后台线程。这二者的区别就是:应用程序必须运行完全部的前台线程才能够退出;而对于后台线程,应用程序则能够不考虑其是否已经运行完毕而直接退出,全部的后台线程在应用程序退出时都会自动结束。
问题:关闭了窗口,消息框还能弹出。

复制代码

  1. private void button1_Click(object sender, EventArgs e)

  2.         {

  3.             //开启一个线程,对js方法进行计算

  4.             ThreadStart ts2 = new ThreadStart(js);

  5.             Thread td2 = new Thread(ts2);            

  6.             td2.Start();

  7.  

  8.         }        

  9.         void js()

  10.         {

  11.             for (int i = 0; i < 2000000000; i++)  //若是看不出效果这里的2后面多加0

  12.             {

  13.                 i++;

  14.             }

  15.             MessageBox.Show("关闭了窗口我仍是要出来的!");

  16.         }

缘由:.Net环境使用Thread创建线程,线程默认为前台线程。即线程属性IsBackground=false,而前台线程只要有一个在运行则应用程序不关闭,因此知道弹出消息框后应用程序才算关闭。
解决办法:在代码中设置td2.IsBackground=true;