多线程学习笔记第三篇
多线程学习笔记第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最好的东西就是能够获取到返回值 }
初心商城:初心商城
作者:韩迎龙(Kencery) MVC/.NET群:159227188如果您认为这篇文章还不错或者有所收获,您可以通过右边的“打赏”功能 打赏一杯咖啡,本页版权归作者和博客园所有,欢迎转载,但未经作者同意必须保留此段声明, 且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利