一、为什么要线程需要同步
线程有可能和其他线程共享一些资源,比如,内存,文件,数据库等。
当多个线程同时读写同一份共享资源的时候,可能会引起冲突。这时候,我们需要引入线程“同步”机制,即各位线程之间要有个先来后到,不能一窝蜂挤上去抢作一团。
线程同步的真实意思和字面意思恰好相反。线程同步的真实意思,其实是“排队”:几个线程之间要排队,一个一个对共享资源进行操作,而不是同时进行操作。
二、常用的线程同步机制。
1. 维护自由锁(InterLocked)实现同步
2. 监视器(Monitor)和互斥锁(lock)
3. 读写锁(ReadWriteLock)
4. 系统内核对象
1) 互斥(Mutex), 信号量(Semaphore), 事件(AutoResetEvent/ManualResetEvent)
2) 线程池
5.Thread.Join方法。这种方法比较简单,当你在第一个线程运行时想等待第二个线程执行结果,那么你可以让第二个线程Join进来就可以了
1.1 自由锁(InterLocked) ---为多个线程共享的变量提供原子操作。该类提供的Add、Increment、Decrement能够完成简单的原子操作
用++或--来操作线程不安全。
2.1 最常见的就是互斥锁(lock),但是对性能影响比较大。
private List<string> AccountList ; //共享对象
try
{
// 等待线程进入
Monitor.Enter(AccountList );
Names.Remove("feige");
Console.WriteLine("Del: {0}", AccountList.Count);
Monitor.Pulse(AccountList);
}
finally
{
// 释放对象锁
Monitor.Exit(AccountList);
}
3.1 读写锁ReadWriteLock
我们读资源的操作要多于写资源的操作。但是如果每次只对资源赋予一个线程的访问权限显然是低效的,
优势:是同时可以有多个线程对同一资源进行读操作。因此在读操作比写操作多很多,并且写操作的时间很短的情况下使用读写锁是比较有效率的。
读写锁是一个非静态类所以你在使用前需要先声明一个读写锁对象:
private static ReaderWriterLock feigeLock= new ReaderWriterLock();
feigeLock.AcquireReaderLock(1000); 请求1秒中读锁
try
{
int inx = _rand.Next(_list.Count); if (inx < _list.Count)
Console.WriteLine("{0}thread {1}", thrdId, _list[inx]);
}
finally{ feigeLock.ReleaseReaderLock(); } 释放读写锁