我是一个菜鸟,我只是在努力,2021正视自己,面对2021!

多线程学习笔记第三篇

多线程学习笔记第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最好的东西就是能够获取到返回值

        }        
posted @ 2012-10-28 21:48  Kencery  阅读(1961)  评论(2编辑  收藏  举报
友情链接:初心商城