当多线程共享一个资源变量的时候,需要对线程加以控制,以保证线程是安全的,共享的资源被有效的使用。
内置锁(监视锁)
synchronized作用域代码块上,是一种内存可见的内置锁。
synchronized是一种可重入锁:同一个线程可以获得它自己持有的锁。
synchronized(x1) {
code1;
synchronized(x2) {
code2;
}
}
显示锁
Lock
ReentrantLock的作用相当于一种内置锁,但不是一种替换内置加锁的方法,而是当内置加锁机制不适用时,作为一种可选择的高级功能。ReentrantLock也提供了可重入的加锁语义,与synchronized相比,它还为处理锁的不可用性问题提供了更高级的灵活性。
Lock lock = new ReentrantLock ();
...
lock.lock()
try {
// 更新对象状态
// 捕获异常,并在必要时恢复不变性条件
}finally {
lock.unlock();
}
锁轮询与定时锁
可定时的与可轮询的锁获取模式是由tryLock方法实现的,与无条件的锁获取模式相比,它具有更完善的错误恢复机制。
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
可中断的锁获取操作
非块结构的加锁
公平性
在公平的锁上,线程将按照它们发出请求的顺序来获取锁,但在非公平的锁上,则允许“插队”。
/**
* 默认获取的是非公平锁
*/
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
读写锁
读写锁实现类ReentrantReadWriteLock继承于ReadWriteLock接口
在读 - 写锁实现的加锁策略中,允许多个读操作同时进行,但每次只允许一个写操作。
synchronized与lock锁的选择
在一些内置锁无法满足需要的情况下,ReentrantLock可以作为一种高级工具。当需要一些高级功能时才应该使用ReentrantLock,这些功能包括:可定时的、可轮询的与可中断的锁获取操作,公平队列,以及非块结构的锁。否则,还是应该优先使用synchronized。