zoukankan      html  css  js  c++  java
  • 多线程系列一

    线程,进程,关系我不就不在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     }
    复制代码

    输出

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

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

    大家多多指教。

    http://www.cnblogs.com/ty408/p/4326195.html

  • 相关阅读:
    Jquery 总结的几种常用操作
    Mybatis 一对多
    HTML 子父窗口 iframe 超时 返回首页
    Struts 标签
    Spring + Mybatis 基于注解的事务
    机器学习实战-数据探索(变量变换、生成)
    机器学习实战-数据探索(变量变换、生成)
    Pandas matplotlib 无法显示中文 Ubuntu16.04
    Pandas matplotlib 无法显示中文 Ubuntu16.04
    Intel MKL FATAL ERROR: Cannot load libmkl_avx2.so or libmkl_def.so.
  • 原文地址:https://www.cnblogs.com/soundcode/p/7238324.html
Copyright © 2011-2022 走看看