七、显示锁
7.1、内置锁synchronized的缺陷
内置锁使用的格式
synchronized(锁对象){ // 获取锁,获取不到会一直阻塞
同步代码块
} // 释放锁
缺陷:
获取锁的线程在无法获取锁的时候,会一直阻塞在获取锁的位置,无法中止,会无限的等待下去。无法对获取不到锁做相关的逻辑操作,也无法设置获取锁的超时时间,也无法强制中断获取锁的操作。
当发生死锁时,只能重启应用解决。
7.2、显示锁Lock
显示锁可以解决上述内置锁的缺陷。
Lock是一个接口,最常用的实现类就是ReentrantLock。
Lock接口代码如下:
public interface Lock {
void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
void unlock();
Condition newCondition();
}
(1)void lock()
获取锁,与内置锁synchronized一样,会一直阻塞在这里,无法中止。
使用方式:
Lock lock =new ReentrantLock();
lock.lock();
try{
需要同步的代码
}finally{
lock.unlock();
}
(2)void lockInterruptibly() throws InterruptedException
获取锁,当收到中断信号后,该方法会抛出InterruptedException中断异常。阻塞中止。
该方法可以被其他线程中断。
使用方法
Lock lock =new ReentrantLock();
try{
lock.lockInterruptibly();
try{
需要同步的代码
}finally{
lock.unlock();
}
}catch(InterruptedException e){
// 获取锁时被中断的处理代码
}
(3)boolean tryLock();
获取锁不会阻塞并立即返回,获取成功返回true,获取失败返回false。
因为可以知道获取锁是否成功,可以执行相关的不同逻辑操作,所以更加灵活了。
使用方法:
Lock lock = new ReentrantLock();
while(true){
boolean isLock = lock.tryLock();
if(isLock){
try{
需要同步的代码
break;
}finally{
lock.unlock();
}
}else{ // else可省略
获取不到锁的处理代码,比如sleep一会再去获取
}
}
(4)boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
获取锁,会阻塞指定时间段,如果在指定时间内获取到锁,会返回true,否则获取失败返回false。同时这个方法是可以被其他线程中断的。
使用方法:
Lock lock = new ReentrantLock();
try{
boolean isLock = lock.tryLock(1000L, TimeUnit.MILLISECONDS);
if(isLock){
try{
需要同步的代码
}finally{
lock.unlock();
}
}else{
超时获取不到锁的代码
}
}catch(InterruptedException e){
被中断的处理代码
}
(5)void unlock();
释放锁,为了保证锁的顺利释放,一般释放锁的代码放在finally块中执行。
(6)Condition newCondition();
获取当前锁的一个等待队列,可以利用wait/notify机制进行通信。
详见笔记九,9.6小节。
7.3、ReentrantLock可重入锁
ReentrantLock内部维护了两个互斥锁,分别是FairSync公平锁和NonfairSync非公平锁,通过ReentrantLock的有参构造public ReentrantLock(boolean fair)决定使用的是哪种锁,默认无参构造使用的是非公平锁。
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
ReentrantLock类图如下:
非公平锁理论上性能比公平锁好,所以最好使用非公平锁。
7.4、读写锁ReadWriteLock
读写锁的接口是ReadWriteLock,实现类是ReentantReadWriteLock
public interface ReadWriteLock {
/**
* Returns the lock used for reading.
*
* @return the lock used for reading
*/
Lock readLock();
/**
* Returns the lock used for writing.
*
* @return the lock used for writing
*/
Lock writeLock();
}
通过readLock()方法获取读锁,读锁就是个Lock;
通过WriteLock()方法获取写锁,写锁也是一个Lock。
读写锁的读锁和读锁是共享的,读锁和写锁是独占的,写锁和写锁时独占的。类似于mysql中的S锁和X锁。
http://ifeve.com/read-write-locks/#simple