深层次解读:(重点从下面第五行开始,我怕你们看了前几行看不下去)
ReentrantLock实现了Lock接口和组合Condition接口的实现类ConditionObject ConditionObject类是在AQS中实现的
ReentrantLock中的lock unlock方法是 它内部抽象类定义的
而ReentrantLock是非公平的,也可以是公平的,lock与unlock如何知道什么时候采用公平的锁策略,什么时候采用非公平的锁策略呢
在源码中可以学到这个核心的思想,我把它称为高级的多态应用:
源码中在ReentrantLock中定义了一个抽象类,Sync它继承于AQS,Sync可以看作一个顶层的调用者,为什么这样讲,在公平锁和非公平锁类的实现中,都是实现了Syn抽象类,然后公平锁和非公平锁的内部有自己独立的lock unlock方法。
重点来了:当我们使用ReentrantLock构造了非公平锁(默认的) 在我们调用ReentrantLock的lock方法时,源码如下:
他会调用sync的lock方法,但是sync是Sync抽象类的一个引用(没对象),lock方法并没有实现,为什么会调用??:
回归正题,ReentrantLock调用lock的时候发生了什么,没有方法为什么可以执行?
这正是我们多态的魅力!!!!!!
因为我们的公平锁和非公平锁是实现了Sync 也就是父类是Sync(如下) Sync的这个方法被子类覆写了,调用父类方法的时候就可以直接调用我们对应子类的方法,于是 如果我们定义的是非公平锁 自然会调用到非公平锁的lock方法, 如果定义的是公平锁,自然会调用到公平锁的Lock方法。过瘾不?非常过瘾(看源码快看晕圈的我看明白了这里,脑瓜子嗡嗡的,应为重点又来了!!!!!!!看下文)
从上面读源码的过程中你还领会到了什么(提示Web开发中。。。。。有感觉吗?)
初学者(比如我)在学web开发的过程中为什么服务层要定义一个Service的接口(可以类比于我们上述源码中的抽象类) 为什么要实现这个接口?为什么不直接使用Service的类,反而定义一个接口,这不是很无聊吗?
当时的我就是上面这个想法,大道至简嘛,搞这么复杂,当时找到的解释是,接口约定了一套业务方法,开发人员需要按照这个标准来执行,有了这个解释我也勉为其难的接受了,它还不是我心中真正的答案,读了上文中的源码后,豁然开朗!!!!
1.写接口是一套约定的业务方法 这只是最浅层,最基础的一个功能
2.随着我们业务的复杂,比如我们具体实现的类到底该采用“公平”模式还是“非公平”模式,就比如我们生活中去银行办业务,高级VIP可以快速办理,普通用户只能排队(钞能力啊!),同样是银行办业务这个方法,我们就可以定义一个银行办业务的接口,然后有两个类来实现他,不同的类实现方法不同,但是我们最后暴露出来的接口仅仅是我们约定好的那个没有方法内容的接口,会根据具体实现的类来自动的执行相应的方法,对不对多态的魅力应该在这里,不是什么乱七八糟的很通俗的:方法名一样,参数不一样无语的讲法。这样我们在写程序的时候,只要定义好接口,有实现类,我们把接口暴露出去任调用,那么我们业务需要添加其他的业务,比如高级VIP也很多了,开展顶级VIP业务,我们不用动我们的架构,直接去写一个顶级VIP的方法,这样实体类是顶级VIP方法,最后我们接口调用的就是它的业务。(好像前几天看了SOA,他大概也就是讲了个这)
3.说到这里Spring框架好像和这个不太相符啊,因为它自动注入了bean,自动实现了接口,如果扩展业务呢,可以自动实现扩展的类吗,头大,我Spring源码还没看。。。回头往这里补吧,有大佬看到这里可以指点一下。
讲到这里,感觉自己顿悟的太舒服了,很满足,就像当初看到级数和泰勒公式和傅里叶变化一样惊奇,这都是认知上突破的惊奇。
同步
ReentrantLock锁如果要同步实现一些逻辑的话,就需要用到Condition这个接口了。ReentrantLock类中有Condition,Condition是被AQS中的ConditionObject实现的。 Condition中的await()相当于阻塞,此时会自动释放锁
例如 两个线程按顺序输出自己的名字50次
public class Main1 { static int value = 0; public static void main(String[] args) { ReentrantLock lock = new ReentrantLock(); Condition con = lock.newCondition(); // A new Thread(() -> { try { lock.lock(); while (value <= 100) { System.out.println(Thread.currentThread().getName() ); con.signal(); con.await();//会自动把锁让出去 阻塞/(等待)在这里 或者说等待在这里 保持同步的功能 } con.signal(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } }, "A").start(); // B new Thread(() -> { try { lock.lock(); while (value <= 100) { System.out.println(Thread.currentThread().getName() ); con.signal(); con.await(); } con.signal(); } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } }, "B").start(); } }
运行结果:
B
A
B
A
B
A
B
A
B
A
B
A
B
A
B
A
B