本文共 8462 字,大约阅读时间需要 28 分钟。
二、串行(同步):
1.lock、Monitor--注意锁定的对象必需是引用类型(string类型除外)
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | private static object syncObject = new object (); private static void TaskWork( object i) { Console.WriteLine( "我是任务:{0}" ,i); lock (syncObject) { Thread.Sleep(1000); Console.WriteLine( "我是任务:{0},线程ID:{1}" ,i,Thread.CurrentThread.ManagedThreadId); } try { Monitor.Enter(syncObject); Console.WriteLine( "我是任务:{0},线程ID:{1}" , i, Thread.CurrentThread.ManagedThreadId); } finally { Monitor.Exit(syncObject); } } //调用 Task.Factory.StartNew(TaskWork,1); Task.Factory.StartNew(TaskWork, 2); |
2.Interlocked
示例:
1 2 3 4 5 6 7 8 9 10 11 12 | int i=1; Interlocked.Increment( ref i); //增量+1=2; Console.WriteLine( "i当前的值:{0}" , i); Interlocked.Decrement( ref i); //减量-1=0; Console.WriteLine( "i当前的值:{0}" , i); Interlocked.Exchange( ref i, 2); //赋值=2; Console.WriteLine( "i当前的值:{0}" ,i); Interlocked.CompareExchange( ref i, 10, 2); //比较交换值,当i=2时,则将i赋值为10; Console.WriteLine( "i当前的值:{0}" , i); |
3.Mutex--可以实现进程间的同步,甚至是两个远程进程间的同步
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | var t1 = new Task(() => { Console.WriteLine( "我是第一个任务!" ); Mutex m = new Mutex( false , "test" ); m.WaitOne(); Console.WriteLine( "第一个任务完成!" ); m.ReleaseMutex(); }); var t2 = new Task(() => { Console.WriteLine( "我是第二个任务!" ); Mutex m = new Mutex( false , "test" ); m.WaitOne(); Console.WriteLine( "第二个任务完成!" ); m.ReleaseMutex(); }); t1.Start(); t2.Start(); |
4.ReaderWriterLock 、ReaderWriterLockSlim--如果在某一时刻资源并没有获取写的独占权,那么可以获得多个读的访问权,单个写入的独占权,如果某一时刻已经获取了写入的独占权,那么其它读取的访问权必须进行等待.
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | static ReaderWriterLock rwLock = new ReaderWriterLock(); static void Read( object state) { Console.WriteLine( "我是读线程,线程ID是:{0}" ,Thread.CurrentThread.ManagedThreadId); rwLock.AcquireReaderLock(Timeout.Infinite); //无限期等待,需要显式调用ReleaseReaderLock释放锁 var readList = state as IEnumerable< int >; foreach ( int item in readList) { Console.WriteLine( "读取当前的值为:{0}" , item); Thread.Sleep(500); } Console.WriteLine( "读完成,线程ID是:{0}" , Thread.CurrentThread.ManagedThreadId); rwLock.ReleaseReaderLock(); } static void Write( object state) { Console.WriteLine( "我是写线程,线程ID是:{0}" , Thread.CurrentThread.ManagedThreadId); rwLock.AcquireWriterLock(Timeout.Infinite); //无限期等待,需要显式调用ReleaseWriterLock释放锁 var writeList = state as List< int >; int lastCount=writeList.Count(); for ( int i = lastCount; i <= 10+lastCount; i++) { writeList.Add(i); Console.WriteLine( "写入当前值:{0}" ,i); Thread.Sleep(500); } Console.WriteLine( "写完成,线程ID是:{0}" , Thread.CurrentThread.ManagedThreadId); rwLock.ReleaseWriterLock(); } //调用: var rwList = new List< int >(); var t1 = new Thread(Write); var t2 = new Thread(Read); var t3 = new Thread(Write); var t4 = new Thread(Read); t1.Start(rwList); t2.Start(rwList); t3.Start(rwList); t4.Start(rwList); |
5.SynchronizationAttribute--确保某个类的实例在同一时刻只能被一个线程访问,类的定义要求:A.类上必需标记SynchronizationAttribute特性,B.类必需继承自System.ContextBoundObject对象
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | [Synchronization(SynchronizationAttribute.REQUIRED, true )] public class Account : System.ContextBoundObject { private static int _balance; public int Blance { get { return _balance; } } public Account() { _balance = 1000; } public void WithDraw( string name, object money) { if (( int )money <= _balance) { Thread.Sleep(2000); _balance = _balance - ( int )money; Console.WriteLine( "{0} 取钱成功!余额={1}" , name, _balance); } else { Console.WriteLine( "{0} 取钱失败!余额不足!" , name); } } } //调用: var account = new Account(); Parallel.Invoke(() => { account.WithDraw( "张三" ,600); }, () => { account.WithDraw( "李四" ,600); }); |
6.MethodImplAttribute--使整个方法上锁,直到方法返回,才释放锁
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | public class Account { private static int _balance; public int Blance { get { return _balance; } } public Account() { _balance = 1000; } [MethodImpl(MethodImplOptions.Synchronized)] public void WithDraw( string name, object money) { if (( int )money <= _balance) { Thread.Sleep(2000); _balance = _balance - ( int )money; Console.WriteLine( "{0} 取钱成功!余额={1}" , name, _balance); } else { Console.WriteLine( "{0} 取钱失败!余额不足!" , name); } } } //调用 var account = new Account(); Parallel.Invoke(() => { account.WithDraw( "张三" ,600); }, () => { account.WithDraw( "李四" ,600); }); |
7.AutoResetEvent、ManualResetEvent、ManualResetEventSlim--调用WaitOne、WaitAny或WaitAll来使线程等待事件,调用Set方法发送信号,事件将变为终止状态,等待的线程被唤醒
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | AutoResetEvent arEvent = new AutoResetEvent( false ); //默认为无信号,处于非终止状态 Task.Factory.StartNew((o) => { for ( int i = 1; i <= 10; i++) { Console.WriteLine( "循环第{0}次" ,i); } arEvent.Set(); //发送信号,处于终止状态 },arEvent); arEvent.WaitOne(); //等待信号,收到信号后则继续下面的执行 Console.WriteLine( "我是主线程,我继续执行!" ); Console.Read(); |
8.Sempaphore、SemaphoreSlim(不可跨进程)--信号量,可实现线程、进程间同步
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | public class WashRoom { private readonly Semaphore sem; public WashRoom( int maxUseableCount) { sem = new Semaphore(maxUseableCount, maxUseableCount, "WC" ); } public void Use( int i) { Task.Factory.StartNew(() => { Console.WriteLine( "第{0}个人等待进入" , i); // WaitOne:如果还有“空位”,则占位,如果没有空位,则等待; sem.WaitOne(); Console.WriteLine( "第{0}个人成功进入,使用中" , i); // 模拟线程执行了一些操作 Thread.Sleep(100); Console.WriteLine( "第{0}个人用完,离开了" , i); // Release:释放一个“空位” sem.Release(); }); } } //调用: var wc = new WashRoom(5); for ( int i = 1; i <= 7; i++) { wc.Use(i); } |
9.Barrier--屏障,使多个任务能够采用并行方式依据某种算法在多个阶段中协同工作,即:将一个阶段的事情分成多个线程来异步执行,执行完毕后再同时进入下一个阶段
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | int taskSize = 5; Barrier barrier = new Barrier(taskSize, (b) => { Console.WriteLine( string .Format( "{0}当前阶段编号:{1}{0}" , "-" .PadRight(15, '-' ), b.CurrentPhaseNumber)); }); var tasks = new Task[taskSize]; for ( int i = 0; i < taskSize; i++) { tasks[i] = Task.Factory.StartNew((n) => { Console.WriteLine( "Task : #{0} ----> 处理了第一部份数据。" , n); barrier.SignalAndWait(); Console.WriteLine( "Task : #{0} ----> 处理了第二部份数据。" , n); barrier.SignalAndWait(); Console.WriteLine( "Task : #{0} ----> 处理了第三部份数据。" , n); barrier.SignalAndWait(); }, i); } Task.WaitAll(tasks); |
10.SpinLock--自旋锁,仅限锁定的时间较短
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | SpinLock sLock = new SpinLock(); int num = 0; Action action = () => { bool lockTaken = false ; for ( int i = 0; i < 10; i++) { lockTaken = false ; try { sLock.Enter( ref lockTaken); Console.WriteLine( "{0}+1={1} ---线程ID:[{2}]" , num, ++num,Thread.CurrentThread.ManagedThreadId); Thread.Sleep( new Random().Next(9)); } finally { //真正获取之后,才释放 if (lockTaken) sLock.Exit(); } } }; //多线程调用: Parallel.Invoke(action, action, action); Console.WriteLine( "合计:{0}" , num); |
11.SpinWait--自旋等待,轻量级
1 2 3 4 5 6 7 8 | Thread.Sleep(1000); //线程等待1S; Console.WriteLine(DateTime.Now.ToString( "yyyy-MM-dd HH:mm:ss.fff" )); SpinWait.SpinUntil(() => false , 1000); //自旋等待1S Console.WriteLine(DateTime.Now.ToString( "yyyy-MM-dd HH:mm:ss.fff" )); Thread.SpinWait(100000); //指定CPU的循环次数,时间间隔处决于处理器的运行速度,一般不建议使用 Console.WriteLine(DateTime.Now.ToString( "yyyy-MM-dd HH:mm:ss.fff" )); |
12.CountdownEvent--与Sempaphore功能类似,但CountdownEvent支持动态调整信号计数
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | static void TimeLimitShopping( int custCount, int times,CountdownEvent countdown) { var customers = Enumerable.Range(1, custCount); foreach ( var customer in customers) { int currentCustomer = customer; Task.Factory.StartNew(()=> { SpinWait.SpinUntil(() => false , 1000); Console.WriteLine( "第{0}波客户购买情况:Customer-{1}-已购买." , times, currentCustomer); countdown.Signal(); }); //countdown.AddCount(); } } //调用: var countdown = new CountdownEvent(5); TimeLimitShopping(5, 1, countdown); countdown.Wait(); countdown.Reset(10); TimeLimitShopping(10, 2, countdown); countdown.Wait(); countdown.Reset(20); TimeLimitShopping(20, 3, countdown); countdown.Wait(); |
最后分享在System.Collections.Concurrent命名空间下的几个并发集合类:
ConcurrentBag<T>:表示线程安全的无序集合;
ConcurrentDictionary<T>:表示线程安全的多个键值对集合;
ConcurrentQueue<T>:表示线程安全的先进先出集合;
ConcurrentStack<T>:表示线程安全的后进先出集合;
线程的几个状态(以下图片来源于这篇文章:http://www.cnblogs.com/edisonchou/p/4848131.html):
参考以下相关文章:
本文转自 梦在旅途 博客园博客,原文链接: http://www.cnblogs.com/zuowj/p/4910512.html ,如需转载请自行联系原作者