你的位置:首页 > ASP.net教程

[ASP.net教程]多线程系列一


线程,进程,关系我不就不在BB了。

关于线程,其实我相信大家都了解了很多,此处我只是发表我对线程的理解和认识,不喜勿喷。如有不对之处还请大家指出。

 1   class Program 2   { 3     static void Main(string[] args) 4     { 5       Thread t = new Thread(Runing); 6       t.Name = "测试线程"; 7       t.Start(); 8       Console.ReadLine(); 9     }10 11     static void Runing()12     {13       Console.WriteLine(Thread.CurrentThread.Name + " :" + DateTime.Now.ToString());14     }15   }

上述代码大家肯定都不陌生~!

 接下来我们修改一下程序,完成单线程处理任务。我们知道很多时候,当我们的程序设计,又多个客户端或者称多个请求来源,并发请求来了以后,我们需要按照队列处理事情比如秒杀下单

public class MyThread1  {    //通知一个或多个正在等待的线程已发生事件    ManualResetEvent mre = new ManualResetEvent(false);    //服务器的运行标识    bool isRuning = true;    //线程安全的队列    System.Collections.Concurrent.ConcurrentQueue<string> cqueue = new System.Collections.Concurrent.ConcurrentQueue<string>();    public MyThread1()    {      Thread t = new Thread(RunTest);      t.Name = "我是测试线程";      t.Start();    }    //模拟新增任务    public void add(int i)    {      //添加任务到队列      cqueue.Enqueue("" + i);      //唤醒所有相关的挂起线程      mre.Set();    }    static void Main(string[] args)    {      MyThread1 p = new MyThread1();      for (int i = 0; i < 10; i++)      {        p.add(i);      }      Console.ReadLine();    }    void RunTest()    {      //主循环 服务器运行标识      while (isRuning)      {        //如果是空则继续等待   服务器运行标识        while (cqueue.IsEmpty && isRuning)        {          Console.WriteLine(DateTime.Now.ToString("HH:mm:ss:ffff") + " : " + Thread.CurrentThread.Name + " sleep");          //重置线程暂停状态          mre.Reset();          //这个操作是以便服务器需要停止操作,          //如果停止调用线程的Thread.Abort()是会导致处理队列任务丢失          mre.WaitOne(2000);        }        string ret;        //取出队列任务        if (cqueue.TryDequeue(out ret))        {          //测试输出任务          Console.WriteLine(DateTime.Now.ToString("HH:mm:ss:ffff") + " : " + Thread.CurrentThread.Name + " " + ret);        }      }    }  }

通过add实现并发下单 RunTest() 方法来实现处理逻辑,

此处通过 ManualResetEvent 实现对线程的挂起和唤醒操作。当队列为空的时候,线程自动进入挂起状态,当有新的任务,add操作的时候直接唤醒挂起的线程。立即进入处理状态。

为什么选用 ManualResetEvent 这个线程通知这里就不在解释了有兴趣的可以自己百度~!

为了避免在需要关闭服务器的时候调用线程的Thread.Abort() 导致后续队列操作失效,所以加入了isRuning的bool变量实现线程是否继续运行。

 

上述功能仅仅是永远类似于处理下单,需要单线程队列处理情况。各位看官请自行分析需求~~!

有了上述单线程处理队列需求,我们也许会想到那么在程序运行中自然有多线程处理队列。

比如我们记录日志的情况,(打个比方而已如果你很喜欢log4Net or log4J 请绕道)  我们需要提交日志记录,但是不想这个操作耽误程序的正常运行,且想日志这样的记录程序肯定不能单一线程处理,

如果日志疯狂记录,那么势必会导致处理不及时内存暴涨溢出问题

于是再次修改一下程序

 1 public class MyThread3 2   { 3     //通知一个或多个正在等待的线程已发生事件 4     ManualResetEvent mre = new ManualResetEvent(false); 5     //服务器的运行标识 6     bool isRuning = true; 7     //线程安全的队列 8     System.Collections.Concurrent.ConcurrentQueue<string> cqueue = new System.Collections.Concurrent.ConcurrentQueue<string>(); 9     //计数存储器10     Dictionary<string, int> cdic = new Dictionary<string, int>();11 12     public MyThread3()13     {14       List<Thread> ts = new List<Thread>();15       for (int i = 0; i < 4; i++)16       {17         Thread t = new Thread(RunTest);18         t.Name = "我是线程(" + i + ")";19         cdic[t.Name] = 0;20         t.Start();21         ts.Add(t);22       }23     }24 25     //模拟新增任务26     public void Add()27     {28       Thread t1 = new Thread(() =>29       {30         for (int i = 0; i < 40; i++)31         {32           //添加任务到队列33           cqueue.Enqueue("日志记录 " + i);34           //唤醒所有相关的挂起线程35           mre.Set();36         }37 38       });39       t1.Start();40 41     }42 43     //输出计数器44     public override string ToString()45     {46       foreach (var item in cdic)47       {48         Console.WriteLine(item.Key + " 计数 " + item.Value);49       }50       return "";51     }52 53 54     static void Main(string[] args)55     {56       MyThread3 p = new MyThread3();57       p.Add();58       Console.ReadLine();59       p.ToString();60       Console.WriteLine();61       Console.ReadLine();62     }63 64     void RunTest()65     {66       //主循环 服务器运行标识67       while (isRuning)68       {69         //如果是空则继续等待   服务器运行标识70         while (cqueue.IsEmpty && isRuning)71         {72           //重置线程暂停状态73           mre.Reset();74           //这个操作是以便服务器需要停止操作,75           //如果停止调用线程的Thread.Abort()是会导致处理队列任务丢失76           mre.WaitOne(2000);77           Console.WriteLine(DateTime.Now.ToString("HH:mm:ss:ffff") + " : " + Thread.CurrentThread.Name + " sleep");78         }79         string ret;80         //取出队列任务81         if (cqueue.TryDequeue(out ret))82         {83           //测试输出任务84           Console.WriteLine(DateTime.Now.ToString("HH:mm:ss:ffff") + " : " + Thread.CurrentThread.Name + " " + ret);85           //添加任务的计数器,为了查看最后线程执行任务的计数86           cdic[Thread.CurrentThread.Name] = cdic[Thread.CurrentThread.Name] + 1;87         }88       }89     }90   }

输出

多个线程实现了对日志记录处理,并且在空闲时间实现线程暂停,有任务唤醒,以保证,不浪费资源同时能即时处理~!

由于第一次写博客,语言组织能力差,大家就看看程序代码和注释吧!

大家多多指教。