• .NET多线程


    参考:

    https://www.cnblogs.com/edisonchou/p/4848131.html

    https://www.cnblogs.com/willick/p/4177977.html#header03

    1、线程 System.Threading.Thread类

    Console.WriteLine("开始测试线程1");
                // 初始化一个线程 thread1
                Thread thread1 = new Thread(Work1);
                // 这时状态:UnStarted
                PrintState(thread1);
                // 启动线程
                Console.WriteLine("现在启动线程");
                thread1.Start();
                // 这时状态:Running
                PrintState(thread1);
                // 让线程飞一会 3s
                Thread.Sleep(3 * 1000);
                // 让线程挂起
                Console.WriteLine("现在挂起线程");
                thread1.Suspend();
                // 给线程足够的时间来挂起,否则状态可能是SuspendRequested
                Thread.Sleep(1000);
                // 这时状态:Suspend
                PrintState(thread1);
                // 继续线程
                Console.WriteLine("现在继续线程");
                thread1.Resume();
                // 这时状态:Running
                PrintState(thread1);
                // 停止线程
                Console.WriteLine("现在停止线程");
                thread1.Abort();
                // 给线程足够的时间来终止,否则的话可能是AbortRequested
                Thread.Sleep(1000);
                // 这时状态:Stopped
                PrintState(thread1);
    View Code

    2、线程池 System.Threading.ThreadPool 类

    static void Main(string[] args)
            {
                string taskInfo = "运行10秒";
                // 插入一个新的请求到线程池
                bool result = ThreadPool.QueueUserWorkItem(DoWork, taskInfo);
                // 分配线程有可能会失败
                if (!result)
                {
                    Console.WriteLine("分配线程失败");
                }
                else
                {
                    Console.WriteLine("按回车键结束程序");
                }
    
                Console.ReadKey();
            }
    
            private static void DoWork(object state)
            {
                // 模拟做了一些操作,耗时10s
                for (int i = 0; i < 10; i++)
                {
                    Console.WriteLine("工作者线程的任务是:{0}", state);
                    Thread.Sleep(1000);
                }
            }
    View Code

    设置最大最小工作者线程,IO线程的数量

    class Program
        {
            static void Main(string[] args)
            {
                // 打印阈值和可用数量
                GetLimitation();
                GetAvailable();
    
                // 使用掉其中三个线程
                Console.WriteLine("此处申请使用3个线程...");
                ThreadPool.QueueUserWorkItem(Work);
                ThreadPool.QueueUserWorkItem(Work);
                ThreadPool.QueueUserWorkItem(Work);
    
                Thread.Sleep(1000);
    
                // 打印阈值和可用数量
                GetLimitation();
                GetAvailable();
                // 设置最小值
                Console.WriteLine("此处修改了线程池的最小线程数量");
                ThreadPool.SetMinThreads(10, 10);
                // 打印阈值
                GetLimitation();
    
                Console.ReadKey();
            }
    
    
            // 运行10s的方法
            private static void Work(object o)
            {
                Thread.Sleep(10 * 1000);
            }
    
            // 打印线程池的上下限阈值
            private static void GetLimitation()
            {
                int maxWork, minWork, maxIO, minIO;
                // 得到阈值上限
                ThreadPool.GetMaxThreads(out maxWork, out maxIO);
                // 得到阈值下限
                ThreadPool.GetMinThreads(out minWork, out minIO);
                // 打印阈值上限
                Console.WriteLine("线程池最多有{0}个工作者线程,{1}个IO线程", maxWork.ToString(), maxIO.ToString());
                // 打印阈值下限
                Console.WriteLine("线程池最少有{0}个工作者线程,{1}个IO线程", minWork.ToString(), minIO.ToString());
                Console.WriteLine("------------------------------------");
            }
    
            // 打印可用线程数量
            private static void GetAvailable()
            {
                int remainWork, remainIO;
                // 得到当前可用线程数量
                ThreadPool.GetAvailableThreads(out remainWork, out remainIO);
                // 打印可用线程数量
                Console.WriteLine("线程池中当前有{0}个工作者线程可用,{1}个IO线程可用", remainWork.ToString(), remainIO.ToString());
                Console.WriteLine("------------------------------------");
            }
        }
    View Code

    3、并发异步

    class Program {
        static void Main(string[] args) {
    
            Thread t1 = new Thread(Working);
            t1.Name = "Thread1";
            Thread t2 = new Thread(Working);
            t2.Name = "Thread2";
            Thread t3 = new Thread(Working);
            t3.Name = "Thread3";
    
            // 依次启动3个线程。
            t1.Start();
            t2.Start();
            t3.Start();
    
            Console.ReadKey();
        }
    
        // 每个线程都同时在工作
        static void Working() {
            // 模拟1000次写日志操作
            for (int i = 0; i < 1000; i++) {
                //  异步写文件
                Logger.Write(Thread.CurrentThread.Name + " writes a log: " + i + ", on " + DateTime.Now.ToString() + ".
    ");
            }// 做一些其它的事件
            for (int i = 0; i < 1000; i++) { }
        }
    }
    

      

    4、并发控制 锁

    class Program {
    
        static bool done;
        static object locker = new object(); // !!
    
        static void Main(string[] args) {
    
            new Thread(Go).Start(); // 在新的线程上调用Go
            Go(); // 在主线程上调用Go
    
            Console.ReadKey();
        }
    
        static void Go() {
            lock (locker) {
                if (!done) {
                    Thread.Sleep(500); // Doing something.
                    Console.WriteLine("Done");
                    done = true;
                }
            }
        }
    }
    View Code

    示例 Logger类 

    调用 write(content)方法,Task.Run (.net 4.5)

    // 用于存放写日志任务的队列
            private Queue<Action> _queue;
    
            // 用于写日志的线程
            private Thread _loggingThread;
    
            // 用于通知是否有新日志要写的“信号器”
            private ManualResetEvent _hasNew;
    
            // 构造函数,初始化。
            private Logger()
            {
                _queue = new Queue<Action>();
                _hasNew = new ManualResetEvent(false);
    
                _loggingThread = new Thread(Process);
                _loggingThread.IsBackground = true;
                _loggingThread.Start();
            }
    
            // 使用单例模式,保持一个Logger对象
            private static readonly Logger _logger = new Logger();
            private static Logger GetInstance()
            {
                /* 不安全代码
                lock (locker) {
                    if (_logger == null) {
                        _logger = new Logger();
                    }
                }*/
                return _logger;
            }
    
            // 处理队列中的任务
            private void Process()
            {
                while (true)
                {
                    // 等待接收信号,阻塞线程。
                    _hasNew.WaitOne();
    
                    // 接收到信号后,重置“信号器”,信号关闭。
                    _hasNew.Reset();
    
                    // 由于队列中的任务可能在极速地增加,这里等待是为了一次能处理更多的任务,减少对队列的频繁“进出”操作。
                    Thread.Sleep(100);
    
                    // 开始执行队列中的任务。
                    // 由于执行过程中还可能会有新的任务,所以不能直接对原来的 _queue 进行操作,
                    // 先将_queue中的任务复制一份后将其清空,然后对这份拷贝进行操作。
    
                    Queue<Action> queueCopy;
                    lock (_queue)
                    {
                        queueCopy = new Queue<Action>(_queue);
                        _queue.Clear();
                    }
    
                    foreach (var action in queueCopy)
                    {
                        action();
                    }
                }
            }
    
            private void WriteLog(string content)
            {
                lock (_queue)
                { // 将任务加到队列
                    _queue.Enqueue(() => File.AppendAllText("log.txt", content));
                }
    
                // 打开“信号”
                _hasNew.Set();
            }
    
            // 公开一个Write方法供外部调用
            public static void Write(string content)
            {
                // WriteLog 方法只是向队列中添加任务,执行时间极短,所以使用Task.Run。
                Task.Run(() => GetInstance().WriteLog(content));
            }
  • 相关阅读:
    202006leetcode刷题记录
    二分查找详解
    并查集
    202005leetcode刷题记录
    基于地震数据的Spark数据处理与分析
    Java日志框架:logback详解
    java 多线程
    Oracle表恢复(truncate)
    关于软件开发,你老板不知道的7件事
    调用oracle 分页存储过程 返回游标数据集
  • 原文地址:https://www.cnblogs.com/caolingyi/p/8534432.html
Copyright © 2020-2023  润新知