同步:
在大多数实际的多线程应用中,两个或两个以上的线程需要共享对同一数据的存取。为了避免多线程引起的对共享数据的讹误,必须学习如何同步存取。
锁对象:
1.synchronized关键字 2.ReentrantLock类
用ReentrantLock 保护代码块的基本结构如下:
myLock.lock(); // a ReentrantLock object
try
{
citicalsection
}
Finally
{
myLock.unlock(); //确保即使抛出异常也会解锁
}
锁是可重入的,因为线程可以重复获得已经持有的锁。锁保持一个持有计数来跟踪对lock方法的嵌套调用。线程在每一次调用lock都要用unlock来释放。
等待获得锁的线程和调用await方法的线程存在本质的不同。一旦一个线程调用await方法,它进入该条件的等待集。当锁可用时,该线程不能马上解除阻塞。它处于阻塞状态,直到另一个线程调用同一条件上的signalAll方法时为止。
调用signalAll不会立即激活一个等待线程。它仅仅解除等待线程的阻塞,以便这些线程可以在当前线程退出同步方法之后,通过竞争实现对对象的访问。
Synchronized关键字
锁和条件的小结:
1、 锁用来保护代码片段,任何时候只能有一个线程执行被保护的代码
2、 锁可以管理试图进入被保护代码的线程
3、 锁可以拥有一个或多个相关的条件对象
4、 每个条件对象管理那些已经进入被保护的代码段但不能运行的线程
读/写锁
(1) 构造一个ReentrantReadWriteLock 对象:
privateReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
(2) 抽取读锁和写锁:
Private LockreadLock = rwl.readLock();
private LockwriteLock = rwl.writeLock();
(3) 对所有的获取的方法加读锁:
public doubleget()
{
readLock.lock();
try{…}
finally{ readLock.unlock();}
}
(4) 对所有的修改方法加写锁:
public voidtransfer(…)
{
writeLock.lock();
try(…)
finally{writeLock.unlock();}
}
阻塞队列:
对于多线程问题,可以通过一个或多个队列以优雅且安全的方式将其形式化。生产者线程先向队列插入元素,消费者线程则取出它们。