1.2线程基础(二)
来源:互联网 发布:hive sql 语法 编辑:程序博客网 时间:2024/06/03 17:22
1.2.1 lock关键字
使用lock关键字来确保当一个线程使用某些资源时,同时其他线程无法使用该资源.
class Counter{ private readonly object _syncRoot = new object(); public int Count { get; private set; } public void Add() { lock (_syncRoot) { Count++; } } public void Sub() { lock (_syncRoot) { Count--; } }}var c = new Counter();//创建多个线程来访问cThread t1 = new Thread(()=> TestCounter(c));Thread t2 = new Thread(() => TestCounter(c));Thread t3 = new Thread(() => TestCounter(c));Thread t4 = new Thread(() => TestCounter(c));Thread t5 = new Thread(() => TestCounter(c));t1.Start();t2.Start();t3.Start();t4.Start();t5.Start();t1.Join();t2.Join();t3.Join();t4.Join();t5.Join();Console.WriteLine("count:"+c.Count);
最后输出count:0,有人可能会说这不是很正常吗,那请自己动手把Counter类中lock部分都移除再试一遍,最后输出就会不一样了!~
变成这样:
public void Add(){ Count++;}public void Sub(){ Count--;}
这是因为如果去掉lock部分,Counter类就不是线程安全的.
当多个线程同时访问counter对象时,第一个线程得到的counter值是10并增加为11,
第二个线程得到的值是11并增加为12,
第一个线程得到counter值12,但递减操作发生前,
第二个线程得到counter值也是12,
第一个线程将12递减为11并存回counter中,
同时第二个线程进行了同样的操作.结果我们进行了两次两次递增操作但只有第一递减操作,
这显然是不对的.
这种情形被称为竞争条件(race condition),竞争条件是多线程环境中导致错误的常见原因.为了确保不会发生以上情形,必须保证当有线程操作counter对象时,所有其他线程必须等待直到当前线程完成操作.我们可以使用lock关键字来实现这种行为.如果锁定了一个对象,需要访问该对象的所有其他线程则会处于阻塞状态,并等待知道该对象解除锁定,但这可能会导致严重的性能问题.
1.2.2 使用Monitor类锁定资源
死锁(deadlock)也是多线程编程中常见的错误.由于死锁将导致程序停止工作,可以使用Monitor类来避免死锁.
class Program{ static void Main(string[] args) { object l1 = new object(); object l2 = new object(); new Thread(()=> LockObject(l1,l2)).Start(); lock (l2) { Console.WriteLine("Monitor.TryEnter 可以避免死锁,在超时后返回false"); Thread.Sleep(1000); if (Monitor.TryEnter(l1,TimeSpan.FromSeconds(5))) { Console.WriteLine("成功获取到一个受保护的资源!"); } else { Console.WriteLine("获取资源超时!"); } } Console.WriteLine("------------------------------------"); new Thread(() => LockObject(l1, l2)).Start(); lock (l2) { Console.WriteLine("这将是一个死锁!"); Thread.Sleep(1000); lock (l1) { Console.WriteLine("成功获取到一个受保护的资源!"); } } Console.WriteLine("End."); Console.ReadKey(); } static void LockObject(object l1,object l2) { lock (l1) { Thread.Sleep(1000); lock (l2); } }}
1.2.3 处理异常
在线程中始终使用try/catch代码块是非常重要的,因为不可能在线程代码之外来捕获异常.
class Program{ static void Main(string[] args) { var t = new Thread(ThreadOne); t.Start(); t.Join(); try { t = new Thread(ThreadTwo); t.Start(); } catch (Exception ex) { Console.WriteLine($"Main:{ex.Message}"); } } static void ThreadOne() { try { Console.WriteLine("Starting a faulty thread..."); Thread.Sleep(1000); throw new Exception("Boom!!!"); } catch (Exception ex) { Console.WriteLine($"ThreadOne:{ex.Message}"); } } static void ThreadTwo() { Console.WriteLine("Starting a faulty thread..."); Thread.Sleep(1000); throw new Exception("Boom!!!"); }}
由上图可见ThreadOne的异常被捕获,但是ThreadTwo的异常未被捕获
- 1.2线程基础(二)
- 线程基础(二)
- java基础---线程二
- 线程同步基础(二)
- Java线程基础(二):Synchronization
- (二)线程同步基础
- Java基础之多线程二
- Java基础之多线程(二)
- 线程基础二--卖票问题
- java线程---基础(二)
- C#中的线程(二) 线程同步基础
- C#中的线程(二) 线程同步基础
- C#中的线程(二) 线程同步基础
- C#中的线程(二) 线程同步基础
- C#中的线程(二) 线程同步基础
- C# 线程(二) 线程同步基础
- C#中的线程(二) 线程同步基础
- Java并发基础(二)-线程池基础
- $.ajax()方法详解
- 《深入理解java虚拟机》笔记:
- Maven+MySql(Spring+Mybatis+SpringMVC+Maven+MySql)项目搭建实例
- js打开新窗口的方法
- iOS实现UIView渐变效果及实现透明功能
- 1.2线程基础(二)
- form提交file类型的input后$_FILES为空
- C# FileSystemWatcher 在监控文件夹和文件时的用法
- 初识Python列表
- java网络编程2—流
- 一、基本数据类型
- spring 后置处理器BeanFactoryPostProcessor和BeanPostProcessor的用法和区别
- Shell 字符串 数组
- STM32使用DMA从串口读数据到内存