zoukankan      html  css  js  c++  java
  • 多线程学习笔记第三篇

    多线程学习笔记第3篇

      前言:这篇博客主要是在上一篇博客的基础上,继续记录了死锁,线程同步和线程池的一些知识,方便我以后继续的学习,在这里贴出来和大家共享一下

    1. 对象池技术模拟

      (1) 如果一些对象创建非常消耗时间和资源,使用非常频繁,这时候可以考虑使用对象池技术

      (2)对象池其实就是一个数组,当我们想用一个对象的时候直接从池子里面取,别的对象也可以从池子里面取

      (3)使用代码模拟对象池Demo添加锁

     namespace ObjectPoolPractice
    
         {
    
                class Program
    
                {
    
                       static void Main(string[] args)
    
                       {
    
                              //定义一个对象池
    
                              MyConnection[] pool = new MyConnection[100];
    
                              int index = 0; //当前对象池中对象的个数
    
                              //定义一个锁对象
    
                              Object objLock = new object();  //可以锁定字符串,但是尽量不要锁定字符串,因为相同的字符串指向的引用相同
    
                              //当然也可以锁定this
    
                              //模拟对象池的使用,生产者和消费者的模拟
    
                              //模拟5个生产者,不停地往对象池里面添加对象
    
                              for (int i = 0; i < 5; i++)
    
                              {
    
                                     Thread thread = new Thread(() =>
    
                                     {
    
                                            while (true)
    
                                            {
    
                                                   //锁的对象必须是引用类型,因为同步索引块在堆上的
    
                                                   //只有Lock同一个对象才能互斥
    
                                                   lock (objLock)//阻塞当前线程,等待拿到当前对象的锁
    
                                                   {
    
                                                          if (index < pool.Length)
    
                                                          {
    
                                                                 Console.WriteLine("生产一个对象");
    
                                                                 //生产对象,并将对象放到池子里面去,生产者
    
                                                                 MyConnection conn = new MyConnection();
    
                                                                 //放到池子里面
    
                                                                 pool[index] = conn;
    
                                                                 index++;
    
                                                          }//执行到最后的时候释放锁
    
                                                          Thread.Sleep(300);
    
                                                   }
    
                                            }
    
                                     });
    
                                     thread.IsBackground = true;
    
                                     thread.Start();
    
                              }
    
                              //模拟10个消费者
    
                              for (int i = 0; i < 10; i++)
    
                              {
    
                                     Thread thread = new Thread(() =>
    
                                     {
    
                                            while (true)
    
                                            {
    
                                                   lock (objLock)
    
                                                   {
    
                                                          if (index > 0)
    
                                                          {
    
                                                                 Console.WriteLine("消费一个对象:" + pool[index - 1].ToString());
    
                                                                   pool[index - 1] = null;
    
                                                                 index--;
    
                                                          }
    
                                                          Thread.Sleep(30);
    
                                                   }
    
                                            }
    
                                     });
    
                                     thread.IsBackground = true;
    
                                     thread.Start();
    
                              }
    
                              Console.ReadLine();
    
                       }
    
                }
    
                //假设创建此对象非常消耗时间
    
                public class MyConnection
    
                {
    
                  }
    
         }

      (4)数据库模仿锁

           1)select * from bank with(nolock) --表示当前表做查询的时候不加锁

      (5)解决死锁的方法是操作资源的顺序一致

    2. 线程同步

      (1) 参考上面的案例代码进行说明

      (2)new在堆上申请内存空间后干了什么

           1)Object objLock = new object();

           2)开辟内存

           3)调用构造函数

           4)同步块索引(复数)

      (3)Lock(语法糖)

           try

           {

                  System.Threading.Monitor.Enter(obj);

           }

          finally

           {

                  System.Threading.Monitor.Exit(obj);

           }

      (4)lock这段代码是怎么运行的,lock语句根本使用的就是Monitor.Enter和Monitor.Exit,也就是说lock(o)时执行Monitor.Enter(this), 大括号结束时执行Monitor.Exit(this).他的意义在于什么呢,对于任何一个对象来说,他在内存中的第一部分放置的是所有方法的地址,第二部分放着一个索引,他指向CLR中的SyncBlock Cache区域中的一个SyncBlock.什么意思呢?就是说,当你执行Monitor.Enter(Object)时,如果object的索引值为负数,就从SyncBlock Cache中选区一个SyncBlock,将其地址放在object的索引中。这样就完成了以object为标志的锁定,其他的线程想再次进行Monitor.Enter(object)操作,将获得object为正数的索引,然后就等待。直到索引变为负数,即线程使用Monitor.Exit(object)将索引变为负数。

      (5)线程同步解决的问题:解决多个线程同时访问同一个资源的时候,进行同步。同一个时间,我们的资源只允许一个线程来访问。

    3. 线程池

      (1) 在程序中,如果某个创建某种对象所需要的代价太高,同时这个对象又可以反复使用,那么我们往往就会准备一个容器,用来保存一批这样的对象。于是乎,我们想要用这种对象时,就不需要每次去创建一个,而直接从容器中取出一个现成的对象就可以了。由于节省了创建对象的开销,程序性能自然就上升了

      (2)ThreadPool class提供了一个线程池,该线程池可用于发送工作项、处理异步 I/O、代表其他线程等待以及处理计时器。 线程池允许在后台运行多个工作,而不需要为每个任务频繁地创建和销毁单独的线程,从而减少了开销。

      (3)普通的Windows应用程序(如控制台或WinForm/WPF),会将其设置为"处理器数 * 250"。也就是说,如果您的机器为2个2核CPU,那么CLR线程池的容量默认上限便是1000,也就是说,它最多可以管理1000个线程同时运行

      (4)WaitCallback是一个委托类型,查看源码是:

           public delegate void WaitCallback(object state);

      (5)线程池Demo

     static void Main(string[] args)
    
       {
    
           Console.WriteLine("主线程是:" + Thread.CurrentThread.ManagedThreadId);
    
           //直接将一个方法教给线程池,在线程池内部的线程空闲的时候自动执行当前传进去的委托方法
    
           for (int i = 0; i < 1000; i++)
    
           {
    
              //一般情况下做异步的都要使用线程池,非常特殊的情况,比如你必须拿到当前线程的实例的时候,那么你可以考虑手动创建线程
    
               //.net很多方面都是用线程池,,比如异步委托,只要是系统内部帮我们分配的线程都是通过线程池里面提供的线程
    
                ThreadPool.QueueUserWorkItem(new WaitCallback(DemoWork),"韩迎龙");
    
            }
    
            Console.ReadLine();
    
       }
    
       private static void DemoWork(object state)
    
       {
    
           //这是由线程池来执行的方法
    
           Console.WriteLine("当前执行的方法的线程是:{0}+{1}", Thread.CurrentThread.ManagedThreadId, state);
    
     }
    
      //可以执行查看一下,这里每个人的机器结果可能都不一样,所以试一下

      (6)线程池支持的最大线程数1023个,默认设置是1000,最小0.

                static void Main(string[] args)
    
            {
    
                int maxThread = 0;
    
                int currentMaxTrhead = 0;
    
                ThreadPool.GetMaxThreads(out maxThread, out currentMaxTrhead); ;
    
                Console.WriteLine("最多线程数是:{0},当前的设置是{1}", maxThread, currentMaxTrhead);
    
               //看最小的和最大的一摸一样
    
                Console.ReadKey();
    
            }
    
            //执行结果是:最多线程数是:1023,当前的设置是1000

         (7)等待线程执行结束

        static void Main(string[] args)
    
            {
    
                int a = 0;
    
                Thread thread = new Thread(() =>
    
                {
    
                    Thread.Sleep(3000);
    
                    for (int i = 0; i < 10; i++)
    
                    {
    
                        a++;
    
                    }
    
                    Console.WriteLine("韩迎龙");
    
                });
    
                thread.IsBackground = true;
    
                thread.Start();
    
                Thread.Sleep(1000);
    
                thread.Abort();  //告诉操作系统,将这个线程关闭
    
                thread.Join(); //让当前线程阻塞,停下来等待thread执行完成
    
                Console.WriteLine(a);
    
                Console.ReadLine();
    
            }

         (8)工作项

            static void Main(string[] args)
    
            {
    
                //工作项:比传统的线程池多了一个返回值
    
                Task<int> task = new Task<int>(a =>
    
                {
    
                    return (int)a;
    
                }, 5);
    
                task.Start();  //调用工作项执行
    
                Console.WriteLine(task.Result);  //task最好的东西就是能够获取到返回值
    
            }        
  • 相关阅读:
    微信开发 缓存处理
    ASP.NET MVC 开发日常笔记
    微信开发笔记
    Kindeditor 编辑代码过滤
    PS 使用技巧
    Javascript 日常开发用到的小知识点
    C# 下载文件
    Javascript 笔记一
    C# 知识巩固三
    文献笔记(五)
  • 原文地址:https://www.cnblogs.com/hanyinglong/p/2744005.html
Copyright © 2011-2022 走看看