Lock与ReentrantLock
Lock接口
- Lock提供了一种无条件的丶可轮询的丶可定时的以及可中断的锁获取操作,所有加锁和解锁的方法都是显式的
public interface Lock{ void lock(); //阻塞的获取锁,知道获取到锁才返回且不可中断 void lockInterruptibly();//可中断的获取锁,在阻塞等待过程中可响应中断 boolean tryLock();//尝试非阻塞的获取锁,调用方法后立即返回,获取锁成功返回true,失败返回false boolean tryLock(long timeout,TimeUnit unit);//限定了一个尝试获取锁的时间,在该时间内会尝试获取锁(成功true,失败false),超出时间后直接返回false void unlock();//释放锁 Condition newCondition();//Condition对象:维护一个条件队列,await() singal()方法可以对其进行操作 }
- Lock提供了一种无条件的丶可轮询的丶可定时的以及可中断的锁获取操作,所有加锁和解锁的方法都是显式的
ReentrantLock类
- ReentrantLock类实现了Lock接口,并提供了与synchronized相同的互斥性和内存可见性,还提供了可重入的加锁语义,提供了更高的灵活性
//Lock接口的标准使用形式 Lock lock = new ReentrantLock(); //... lock.lock();//获取锁 try{ //处理 } finally{ lock.unlock();//释放锁一定要在finally块中 }
- ReentrantLock类实现了Lock接口,并提供了与synchronized相同的互斥性和内存可见性,还提供了可重入的加锁语义,提供了更高的灵活性
轮询锁与定时锁
- 可定时的与可轮询的锁获取模式是由tryLock方法实现的,可以避免死锁的发生
//通过tryLock来避免锁顺序死锁(非阻塞避免死锁) try{ if(fromAcct.lock.tryLock()){ //尝试获取锁,直接返回结果,非阻塞(true,false) try{ if(toAcct.lock.tryLock()){//尝试获取锁,直接返回结果,非阻塞 //其他 } } finally{ toAcct.lock.unlock(); } } } finally{ fromAcct.lock.unlock(); }
//带有时间限制的加锁(在timeout时间内没有获取到锁就返回false) if(!lock.tryLock(timeout,unit)) return false; try{ //获取锁成功时操作 return doSomething(); } finally{ lock.unlock(); }
- 可定时的与可轮询的锁获取模式是由tryLock方法实现的,可以避免死锁的发生
可中断的获取锁操作
//可中断的锁获取操作 public boolean sendOnSharedLine(String message) throws InterruptedException{//中断会抛出InterruptedException异常 lock.lockInterruptibly(); //可中断的获取锁 try{ return cancellableSendOnShareLine(message); } finally{ lock.unlock(); } }
公平锁与非公平锁
- ReentrantLock构造函数中提供了两种公平性选择: 创建一个非公平锁(默认)或一个公平锁
- 公平锁上,线程将按照他们发出请求的顺序来获取锁,非公平锁则允许插队
synchronized与ReentrantLock之间的选择
- 在一些内置锁无法满足需求的情况下,ReentrantLock可以作为一种高级工具,当需要一些高级功能时才应该使用ReentrantLock,这些功能包括: 可定时的丶可轮询丶与可中断的锁获取操作,公平队列,以及非块结构的锁,否则还是应该优先使用synchronized
读写锁
public interface ReadWriteLock{ Lock readLock(); //获取读锁 Lock writeLock(); //获取写锁 }
- 读写锁加锁策略中,允许多个读操作同时进行,但是每次只允许一个写操作