• Threads concepts


    (一)线程--简述线程概述及原理 
    线程是程序执行的基本原子单位. 一个进程可以由多个线程组成.
    在分布式编程中,正确使用线程能够很好的提高应用程序的性能及运行效率. 

    实现原理是将一个进程分成多个线程,然后让它们并发异步执行,来提高运行效率.

    并发执行并不是同时执行(占有CPU),任意时刻还是只能有一个线程占用CPU,
    只不过是它们争夺CPU频繁一些,感觉到他们似乎都在运行.

    下面通过一个简单的例子来说明一下它的工作原理

    设一个进程要完成两个任务:任务1和任务2
     并且任务1要经历: A1
    ->B1->C1三个步骤才能完成
         任务2要经历: A2
    ->B2->C2三个步骤才能完成
      I.如果两个任务同步执行的话完成两个任务是这样执行的:
        
        花费时间段:   
    1   2   3   4   5  6
                     A1
    ->B1->C1->A2->B2-C2
        
         这样从A1一直到c2只能一个一个地执行. 当A1占用CPU执行时,从B1到C2线程只能在等待.  
         甚至它们不相互竞争同一个资源时,也要等待前面的执行完成,自己才能执行


      II.如果两个任务异步执行的话完成两个任务是这样执行的:
       
        花费时间段:   
    1   2   3   4   5  6    
                      A1
    ->B1->C1
                      A2
    ->B2->C2 
        
         这样,任务1和任务2就分成两个独立的执行对象.  也就是说: 
         A1
    ->B1->C1 和 A2->B2->C2 是并发执行的. 当A1在执行某个运算时,A2线程可以去做其它
         的一些事情,比如访问磁盘等外部设备等

          对比一下I和II两种执行方式,完成所有任务I需要6个时间段,
      而II只需要3个时间段就完成了(事实上会多一点,因为方式II中的线程轮询CPU比较频繁,在轮询CPU时会花费一些时间);方式II所需时间是I的一半. 所以II完成整个任务要快.
          另一方面,II执行方式,完成每个任务所需的时间可能会花费时间长些,因为I方式是各个线程依次占用CPU执行,当A1占用CPU时,CPU就只为A1服务,当A1执行完后,才让出CPU。II情况就不一样了,它们是异步执行的,轮流使用CPU频繁,经常让出或占有CPU,执行每个线程完成的时间也就会相对长些.

        一般情况下,如果多个线程在执行时都要抢占某一个资源或某几个资源,则最好不用异步线程执行.因为它们是并发执行,很可能同时争夺某个资源有CPU,这时要么执行资源分配算法(比如要判断哪个线程优先级高,这要花费时间),或者是按时间片算法(这样要付出 轮询CUP
    /交接/让出CPU 所需的时间).  如果多个线程所需要的系统资源是比较均匀的,这时完全可以让它们异步并发执行,比如: 当一个线程在给客户端
    发出消息后,并不是一直在等待此客户端回应,它可以继续处理下一个客户端请求.  

    (二)线程
    --通过委托异步调用方法 
    (一).描述
      先运行个简单的线程示例,认识一下线程
      通过委托调用方法,以及使用AsyncResult判断线程的状态

    (二).代码
    using System;
    using System.Threading;
    using System.Runtime.Remoting.Messaging;

    namespace 通过委托异步调用方法

     
    //委托声明(函数签名)
     delegate string MyMethodDelegate();

     
    class MyClass
     {
      
    //要调用的动态方法
      public string MyMethod1()
      {
       
    return "Hello Word1";
      }

      
    //要调用的静态方法
      public static string MyMethod2()
      {
       
    return "Hello Word2";
      }
     }
     
    class Class1
     {
      
    /// 
      
    /// 应用程序的主入口点。
      
    /// 

      [STAThread]
      
    static void Main(string[] args)
      {
                MyClass myClass 
    = new MyClass();
       
       
    //方式1:  声明委托,调用MyMethod1
       MyMethodDelegate d = new MyMethodDelegate(myClass.MyMethod1);
       
    string strEnd = d();   
       Console.WriteLine(strEnd);

       
    //方式2:  声明委托,调用MyMethod2 (使用AsyncResult对象调用)
       d = new MyMethodDelegate(MyClass.MyMethod2); //定义一个委托可以供多个方法使用      
       AsyncResult myResult;   //此类封闭异步委托异步调用的结果,通过AsyncResult得到结果.
       myResult = (AsyncResult)d.BeginInvoke(null,null);        //开始调用
       while(!myResult.IsCompleted)  //判断线程是否执行完成
       {
        Console.WriteLine(
    "正在异步执行MyMethod2 ..");
       }
       Console.WriteLine(
    "方法MyMethod2执行完成!");
       strEnd 
    = d.EndInvoke(myResult);      //等待委托调用的方法完成,并返回结果  
       Console.WriteLine(strEnd);
       Console.Read();
      }
     }
    }


    (三)线程
    --等待句柄
    (一).描述
        本示例代码实现线程等待等待执行,比如一个线程在执行之前要等待所有其它线程或某个线程
    先执行完成,或者等待其它线程至少一个执行完成.
    (二).代码
        
    using System;
        
    using System.Runtime.Remoting.Messaging;
        
    using System.Threading;

    namespace 等待句柄

     
    //委托声明(函数签名)
     delegate string MyMethodDelegate();
     
    class MyClass
     { 
      
    //要调用方法1
      public string Write1()
      {
       
    for(double i = 0; i < 100000000000;i++)  //此数值大小可以根据自己的环境修改,
                                                                     
    //目的是让此方法延长时间而已
       {
        
    //延长时间(模拟实际任务)
       }
       Console.WriteLine(
    "执行方法1");
       
    return "";
      }

      
    //要调用方法2
      public string Write2()
      {
       Console.WriteLine(
    "执行方法2");
       
    return "22222222222222";
      }

      
    //要调用方法3
      public string Write3()
      {
       Console.WriteLine(
    "执行方法3");
       
    return "33333333333333";
      }

      [STAThread]
      
    static void Main(string[] args)
      {
       MyClass myClass 
    = new MyClass();
       MyMethodDelegate d1 
    = new MyMethodDelegate(myClass.Write1);
       MyMethodDelegate d2 
    = new MyMethodDelegate(myClass.Write2);
       MyMethodDelegate d3 
    = new MyMethodDelegate(myClass.Write3);

       AsyncResult myResult1,myResult2,myResult3;     
    //此类封闭异步委托异步调用的结果,通过AsyncResult得到结果.
       myResult1 = (AsyncResult)d1.BeginInvoke(null,null);        //调用   
       
       myResult2 
    = (AsyncResult)d2.BeginInvoke(null,null);        
       
       myResult3 
    = (AsyncResult)d3.BeginInvoke(null,null); 

       
    //建立WaitHandle数组对象
       WaitHandle[] waitHandle = new WaitHandle[3]{myResult1.AsyncWaitHandle,myResult2.AsyncWaitHandle,myResult3.AsyncWaitHandle};

    /* 
          try
       {
        //等待三个异步方法中的至少一个执行完成,才继续执行下面的语句
        WaitHandle.WaitAny(waitHandle);
       }
       catch(Exception ex)
       {
        throw new Exception(ex.Message);
       }
    */

       myResult1.AsyncWaitHandle.WaitOne();  
    //如果当前异步方法还没有完成,此异步方法执行完毕才往下执行
       myResult2.AsyncWaitHandle.WaitOne();  
       myResult3.AsyncWaitHandle.WaitOne();

    /*
       myResult1.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(1),false); //如果当前异步方法还没有完成,则等待一秒的时间执行此方法; 如果一秒后此方法还未完成的话,则不再等待,继续往下执行
       myResult2.AsyncWaitHandle.WaitOne();  
       myResult3.AsyncWaitHandle.WaitOne();
    */  
       
       Console.WriteLine(
    "测试等待句柄");   //标记语句用.
       Console.Read();
      }
     }
    }

    (四)线程
    --使用线程回调方法 
    (一).描述
       此示例演示使用线程回调方法
    (二).代码
       
    using System;
    using System.Threading;
    using System.Runtime.Remoting.Messaging;

    namespace 回调

     
    //委托声明(函数签名)
     delegate string MyMethodDelegate();

     
    class MyClass
     {
      
    //调用的方法
      public static string MyMethod()
      {   
       
    //Console.WriteLine(System.Threading.Thread.CurrentThread.IsBackground);
       for(int i = 0;i < 3; i++)  //延长时间(模拟实际任务)
       {
        Thread.Sleep(
    1000);
       }
       
    return "Hello Word";
      }
      
      
    //声明委托,调用MyMethod
      private static MyMethodDelegate d = new MyMethodDelegate(MyClass.MyMethod);
      
      
    //声明委托,调用AsyncCallbackMethod
      private static System.AsyncCallback a = new System.AsyncCallback(MyClass.AsyncCallbackMethod);  
      
      [STAThread]
      
    static void Main(string[] args)
      {
       d.BeginInvoke(a,
    null); 
       Console.ReadLine();   
    //这句不能去掉,否则主线程执行完成后,子线会会强迫调用Abort()方法销毁掉,也就执行不到回调方法了
      }  
      
      
    public static void AsyncCallbackMethod(System.IAsyncResult myIAsyncResult)
      {
       
    string strEnd = d.EndInvoke(myIAsyncResult);      //委托调用的方法已经完成,输出其值  
       Console.WriteLine(strEnd);
       Console.Read();
      }
     }
    }

    (五)线程
    --定制线程及设置和获取线程的优先级别 
    (一).描述
       此示例演示怎样定制一个线程,并且设置线程的主要属性和获取线程运行时的状态
    (二).代码

       
    using System;
    using System.Threading;
    namespace 定制线程
    {
     
    //委托声明(函数签名)
     
    //delegate string MyMethodDelegate();
     class MyClass
     {  
      
    public static void Method1()
      {
       
    int i;
       
    for(i=0;i<10;i++)
       {
        Console.WriteLine(
    "Method1 at :" + i.ToString());
        
        
    //当线程停止/失败或未启动时IsAlive值为:false,否则为:true;
        Console.WriteLine("    IsAlive is " + Thread.CurrentThread.IsAlive.ToString()+" ");    
                    
        
    //是否是后台进程
        Console.WriteLine("    IsBackGround is " + Thread.CurrentThread.IsBackground.ToString()+" ");    
        
        
    //线程名称
        Console.WriteLine("    Name is " + Thread.CurrentThread.Name.ToString()+" ");    
        
        
    //优先级
        Console.WriteLine("    Priority is " + Thread.CurrentThread.Priority.ToString()+" ");    
        
        
    //ThreadState值组合,有:启动/运行/等待/是否是后台线程等状态. 通过此属性来判断该线程是否完成任务.
        Console.WriteLine("    ThreadState is " + Thread.CurrentThread.ThreadState.ToString()+"\n\n ");    

        DelayTime(
    1);  //延长时间,模拟执行任务
       }
      }
      
    public static void Method2()
      {
       
    int i;
       
    for(i=0;i<10;i++)
       {
        Console.Write(
    "Method2 at :" + i.ToString());

        
    //当线程停止/失败或未启动时IsAlive值为:false,否则为:true;
        Console.WriteLine("    IsAlive is " + Thread.CurrentThread.IsAlive.ToString()+" ");    
                    
        
    //是否是后台进程
        Console.WriteLine("    IsBackGround is " + Thread.CurrentThread.IsBackground.ToString()+" ");    
        
        
    //线程名称
        Console.WriteLine("    Name is " + Thread.CurrentThread.Name.ToString()+" ");    
        
        
    //优先级
        Console.WriteLine("    Priority is " + Thread.CurrentThread.Priority.ToString()+" ");    
        
        
    //ThreadState值组合,有:启动/运行/等待/是否是后台线程等状态. 通过此属性来判断该线程是否完成任务.
        Console.WriteLine("    ThreadState is " + Thread.CurrentThread.ThreadState.ToString()+"\n\n ");           

        DelayTime(
    1);  //延长时间,模拟执行任务
       }
      }
      
    private static void DelayTime(int n)
      {
       DateTime startTime 
    = DateTime.Now;
       
    while(startTime.AddSeconds(n) > DateTime.Now)
       {
        
    //延长时间,模拟实际中的进程
       }
      }

      [STAThread]
      
    static void Main(string[] args)
      {           
    //   MyMethodDelegate d1 = new MyMethodDelegate(MyClass.Method1);
    //   MyMethodDelegate d2 = new MyMethodDelegate(MyClass.Method2);
       
       Thread thread1 
    = new Thread(new ThreadStart(Method1));
       thread1.Name 
    = "A";   //给线程定义名称
       
    //ThreadPriority枚举共五种优先级,由高->低依次为: Highest->AboveNormal->Normal->BelowNormal->Lowest
       
    //优先级高的先优先执行,相同优先级的线程具有相同对CPU争夺权力
       thread1.Priority = ThreadPriority.Highest; 

                Thread thread2 
    = new Thread(new ThreadStart(Method2));   
       thread2.Name 
    = "B";
       thread2.Priority 
    = ThreadPriority.Normal;

                thread1.Start();
       thread2.Start();
       Console.Read();
      }
     }
    }

    (六)线程
    --分别用lock以及Interlocked和Monitor类实现线程的临界区操作(互斥) 
    (一).描述
       此示例演示分别用lock以及Interlocked和Monitor类实现线程的临界区操作(互斥)
    (二).代码
       
    using System;
    using System.Threading;
    using System.Collections;

    namespace 加锁_实现临界区互斥操作_

     
    //委托声明(函数签名)
     delegate string MyMethodDelegate();

     
    class MyClass
     {  
      
    private static ArrayList arrList = new ArrayList(); 
      
    private static int i = 0;
      
      
    public static void Add()
         {
       
    //方法一:用 lock 实现
    //   lock(arrList)
    //   {
    //    arrList.Add(i.ToString());
    //    i++;
    //   }
       
       
    //方法二: 用Interlicked类实现
    //   System.Threading.Interlocked.Increment(ref i);
    //   arrList.Add(i.ToString());

       
    //方法三: 用Monitor类实现
       try
       {
        
    //I.不限时间
        
    //stem.Threading.Monitor.Enter(arrList);  
        
        
    //II.在指定时间获得排他锁
        if(System.Threading.Monitor.TryEnter(arrList,TimeSpan.FromSeconds(30))) //在30秒内获取对象排他锁. 灵活运用可以实现防止死锁功能
        {                                                                       //避免互相等待情况。 在一定时间内得不到排他锁,可能是自己
                                                                             
    //占用其它排它锁造成的(别的正在等自己正占用的排它锁,而处于等待状态),
                                                                             
    //这时可以释放掉自己正占用的排他锁后,再试图去得到想要的对象的排他锁
         arrList.Add(i.ToString());                                        
         i
    ++;
        }
       }
       
    catch
       {
        
    //发生异常后自定义错误处理代码
       }
       
    finally
       {
        Monitor.Exit(arrList);  
    //不管是正常还是发生错误,都得释放对象
       }
      } 
      
      [STAThread]
      
    static void Main(string[] args)
      {
       Thread thread1 
    = new Thread(new ThreadStart(Add));
       Thread thread2 
    = new Thread(new ThreadStart(Add));  
       Thread thread3 
    = new Thread(new ThreadStart(Add)); 
       thread1.Start();
       thread2.Start();
       thread3.Start();

       Console.Read();

       
    for(int i=0;i<arrList.Count;i++)
       {
        Console.WriteLine(arrList[i].ToString());
       }

       Console.Read();

      }
     }
    }

    (七)线程
    --管理线程(使线程中止,暂停,挂起等) 
    (一).描述
       此示例演示怎样设置线程的状态(中止,暂停,挂起等)
    (二).代码
       
    using System;
    using System.Threading;

    namespace 管理线程_使线程中止_暂停_挂起等_

     
    //委托声明(函数签名)
     delegate string MyMethodDelegate();
     
    class MyClass
     {  
      
    public static void Method1()
      {
       
    //thread1.Abort();一句中的 Abort会引发异常System.Threading.ThreadAbortException,其异常作用,下面会讲解   
       try
       {
        
    int i;
        
    for(i=0;i<10;i++)
        {
         Console.WriteLine(
    "Method1 at :" + i.ToString());  
         DelayTime(
    1);  //延长时间(模拟执行任务)
        }
       }
       
    catch(System.Threading.ThreadAbortException)
       {
        
    //注意一点,线程跳出此语句块后才终止。
        
    //这里可以写释放此进程占用的资源代码,或者其它一些操作,比如: 在进程结束前将重要数据写回数据库中
        Console.WriteLine("进程1马上将被强制杀死!"); 
        Thread.ResetAbort();  
    //取消Abort()操作,我在这里加这句没用,反而出现异常了,读者如果知道,请告诉我怎样写才对   
       }
      }
      
    public static void Method2()
      {
       
    int i;
       
    for(i=0;i<10;i++)
       {
        Console.WriteLine(
    "Method2 at :" + i.ToString());  
        DelayTime(
    1);  //延长时间,模拟执行任务
       }
      }
      
      
    private static void DelayTime(int n)
      {
       DateTime startTime 
    = DateTime.Now;
       
    while(startTime.AddSeconds(n) > DateTime.Now)
       {
        
    //延长时间,模拟实际中的进程
       }
      }

      [STAThread]
      
    static void Main(string[] args)
      {              
       Thread thread1 
    = new Thread(new ThreadStart(Method1));   
       Thread thread2 
    = new Thread(new ThreadStart(Method2));   
       thread1.Start();
       thread2.Start();
       thread1.Abort(); 
    //将线程强制终止(杀死)   
                
       
    //thread1.Join的作用是无限制等待thread1终止后,才执行下面的语句,起到与主线程同步的作用.
       
    //原因是: thread1最终是被终止的,但是thread1一个独立的线程,它并不会马上被终止。
       
    //什么时候用:就拿这里来举例吧,当thread1占用着一个资源,当thread1终止后,
       
    //thread2线程马上也要用此资源,这就要求等待thread1彻底终止并释放后占用资源后,才能接着执行下一句,
       
    //否则线程thread2会找不到此资源,甚至会发生异常错误! 为了安全起见,一般是要在Abort()方法后面紧跟一个Join()方法的.
       
       
                
    //thread1.Suspend();//此方法将线程无限制时间的挂起,相当于无限制时间的暂停线程
                
    //thread1.Resume(); //将正在挂起的进程继续执行
       
       
    //Thread.Sleep(1000);//暂停线程1秒钟,以毫秒为单位暂停.
       
       
    //Thread.ResetAbort();     //取消Abort()操作
       
    //thread1.Interrupt(); //中止线程现在处的状态。如果线程由运行转到休眠,执行此句后,会使线程重新返回到运行状态
                
       Console.Read();
      }
     }
    }

     (八)线程
    --借助 封装类 实现“线程调用带参方法”
    (一).描述
          由于线程只能执行无参数方法. 有时候需要线程执行
    "带参数方法"
          此示例演示怎样借助封装类实现“线程调用带参方法”
    (二).代码
       
    using System;
    using System.Threading;

    namespace 借助封装类实现_线程调用带参方法_
    {
     
    class Help
     {
      
    public int x = 0;  //乘数1
      public int y = 0;  //乘数2
      public int end = 0//存放结果
     }
     
    class MyClass
     {  
      
    public static Help  myHelp = new Help();
            
              
      [STAThread]
      
    static void Main(string[] args)
      { 
                
    //给类的成员赋值
       myHelp.x = 5;
       myHelp.y 
    = 10;                 
       
       Thread thread 
    = new Thread(new ThreadStart(GetAccumulate));
                thread.Start();

       Thread.Sleep(
    1000); //主线程等待子线程计算完成,否则取得的值为默认值 : 0
       
       Console.WriteLine(
    "两数乘积结果为: "+myHelp.end.ToString());

       Console.Read();
       
      }

      
    /// 
      
    /// 得到两个整数的集
      
    /// 

      
    /// 乘数x
      
    /// 乘数y
      
    /// x*y
      public static void GetAccumulate()
      {
       myHelp.end 
    = myHelp.x * myHelp.y;
      }
     }
    }




  • 相关阅读:
    《疯狂的程序员》二
    《当程序员的那些狗日日子》五
    《疯狂的程序员》九
    《疯狂的程序员》一
    《疯狂的程序员》三
    和菜鸟一起学算法之递归和分治简单实例
    《疯狂的程序员》八
    《当程序员的那些狗日日子》四
    开放源代码软件利润高于专有代码
    少年黑客破解Google视频播放器
  • 原文地址:https://www.cnblogs.com/hq2008/p/829922.html
Copyright © 2020-2023  润新知