可以看到ReentrantLock继承自Lock接口,它提供了一些获取锁和释放锁的方法,以及条件判断的获取的方法,通过实现它来进行锁的控制,它是显示锁,需要显示指定起始位置和终止位置,Lock接口的方法介绍:
方法名称 方法描述lock 用来获取锁,如果锁已被其他线程获取,则进行等待。
tryLock 表示用来尝试获取锁,如果获取成功,则返回true,如果获取失败(即锁已被其他线程获取),则返回false,也就说这个方法无论如何都会立即返回。在拿不到锁时不会一直在那等待
tryLock(long time, TimeUnit unit) 和tryLock()类似,区别在于它在拿不到锁时会等待一定的时间,在时间期限之内如果还拿不到锁,就返回false。如果如果一开始拿到锁或者在等待期间内拿到了锁,则返回true
lockInterruptibly 获取锁,如果获取锁失败则进行等到,如果等待的线程被中断会相应中断信息。
unlock 释放锁的操作
newCondition 获取Condition对象,该组件和当前的锁绑定,当前线程只有获得了锁,才能调用该组件wait()方法,而调用后,当前线程释放锁。
ReentrantLock也实现了上面接口的内容,前面讲解了很多理论行的内容,接下来我们以一个简单的例子来进行探讨
public class ReentrantLockDemo { public static void main(String[] args) throws Exception { AddDemo runnalbeDemo = new AddDemo(); Thread thread = new Thread(runnalbeDemo::add); thread.start(); Thread thread1 = new Thread(runnalbeDemo::add); thread1.start(); Thread.sleep(1000); System.out.println(runnalbeDemo.getCount()); } private static class AddDemo { private final AtomicInteger count = new AtomicInteger(); private final ReentrantLock reentrantLock = new ReentrantLock(); private void add() { try { reentrantLock.lock(); count.getAndIncrement(); } finally { // reentrantLock.unlock(); } } int getCount() { return count.get(); } } }首先声明内部类AddDemo,AddDemo的主要作用是将原子变量count进行递增的操作
AddDemo内部声明了ReentrantLock对象进行同步操作
AddDemo的add方法,进行递增操作,细心地同学发现,使用了lock方法获取锁,但是没有释放锁,这里面没有释放锁可以更让我们清晰的分析内部结构的变化。
主线程开启了两个线程进行同步进行递增的操作,最后让线程休眠一会输出累加的最后结果。
ReentrantLock内部提供了两种AQS的实现,一种公平模式,一种是非公平模式,如果没有特别指定在构造器中,默认是非公平的模式,我们可以看一下无参的构造函数。
public ReentrantLock() { sync = new NonfairSync(); }当调用有参构造函数时,指定使用哪种模式来进行操作,参数为布尔类型,如果指定为false的话代表非公平模式,如果指定为true的话代表的是公平模式,如下所示:
public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); }我们使用的是非公平模式,后面再来进行分析公平模式,上面也讲到了分为两种模式,这两种模式为FairSync和NonfairSync两个内部静态类不可变类,不能被继承和实例化,这两个类是我们今天分析的重点,为什么说是重点呢,这里讲的内容是有关于AQS的,而FairSync和NonfairSync实现了抽象内部类Sync,Sync实现了AbstractQueuedSynchronizer这个类,这个类就是我们说的AQS也是主要同步操作的类,下面我们来看一下公平模式和非公平模式下类的继承关系,如下图所示:
非公平模式:
公平模式:
通过上面两个继承关系UML来看其实无差别,差别在于内部实现的原理不一样,回到上面例子中使用的是非公平模式,那先以非公平模式来进行分析,
假设第一个线程启动调用AddDemo的add方法时,首先执行的事reentrantLock.lock()方法,这个lock方法调用了sync.lock(),sync就是我们上面提到的两种模式的对象,来看一下源码内容:
public void lock() { sync.lock(); }