1、可重入锁
ReentrantLock的中文名叫重入锁,意思就是一个线程可以多次地重新进入这个锁以及它的父类的锁,而不需要等待或者竞争锁。
ReentrantLock和Synchronized都是可重入锁,两者实现可重入的方法一样,都是通过锁计数器实现的,每次加锁,锁计数器加1,每次解锁,锁计数器减1。当计数器为0时,说明锁释放了。
2、高级用法
1)可中断式加锁
使用lock.interruptibly()代替lock.lock(),表示锁可以被外部中断;
中断的方式是使用lock.interrupt()。
2)限时等待锁
使用lock.tryLock(1000,TIMEUNIT.MILLISECONDS),表示所有的线程在申请锁的时候,若锁还没有被释放,都可以等待1秒钟。
3)公平锁
ReentrantLock默认是非公平锁,所有的线程通过自旋的方式获得锁。
ReentrantLock提供公平锁的方式,只需要在创建对象的指定就可以:
ReentrantLock lock = new ReentrantLock(true);
这里提一下,Synchoronized是不公平锁,因为会自旋等待,自旋可能会抢占线程。
4)分组等待
Synchronized的线程间等待和通知只能一下子通知使用某个object的所有的线程,没法做到等待和通知部分线程,这样效率不高。
ReentrantLock可以通过申明多个Condition来进行分组等待,每一组线程使用一个Condition,这样提高了效率。
3、ReentrantReadWriteLock
ReentrantLock是独占锁,只能有一个线程使用这个锁。ReentrantReadWriteLock是非独占锁,是一种可重入读写锁,意思就是在ReentrantLock的基础之上,它提供读与写分离的机制。
ReentrantReadWriteLock区分读锁和写锁,一旦读锁锁住了,就不能写,但是可以读;一旦写锁锁住了,不能读也不能写。
用起来很简单,先申明一个ReentrantReadWriteLock,然后申请读锁和写锁:
private static ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private static Lock readLock = readWriteLock.readLock();
private static Lock writeLock = readWriteLock.writeLock();
对于readLock,直接使用readLock.lock()和readLock.unlock()进行加锁解锁;
对于writeLock,同样是使用lock()和unlock()方法进行加锁和解锁。
一旦有线程进入writeLock代码块,那么其它线程既不能进入writeLock代码块,也不能进入readLock代码块。
一旦有线程进入readLock代码块,那么其它线程也可以进入readLock代码块,但是不能进入writeLock代码块。
4、ReentrantLock实现原理
ReentrantLock的实现是基于AQS来做的,其内部有两个静态内部类:
FairSync:是公平锁;NonFairSync:是非公平锁。
AQS是基于CAS来实现的,通过自旋来获取锁资源。
5、Await\signal\signalAll
ReentrantLock的这三个方法对应Synchronized的wait\notify\notifyAll方法,用来解决使用ReentrantLock加锁以后各线程之间的通信问题,用法完全一样。
Synchronized在使用wait\notify\notifyAll方法时,是通过对一个对象加锁,然后通过对象的wait\notify\notifyAll方法来等待或通知其它线程;
ReentrantLock在使用Await\signal\signalAll方法时,是使用ReentrantLock内部的Condition对象,来进行await\signal\signalAll操作。
网友评论