锁,中华字典解释:置于可启闭的器物上,以钥匙或暗码(如字码机构、时间机构、自动释放开关、磁性螺线管等)打开的扣件〖lock〗(链接)。咱们可以这样理解,锁就是一种监视器,只有掌握密码(符合某种条件)才能进入。好了,那我们看下java在不同的场景来实现这个保护层的吧。
synchronized 是java的关键字,底层实现是由JVM 实现的(Java synchronized原理总结)。
Lock 是java 1.5提供的锁的接口,根据不同的场景JDK 为我们提供了重入锁,读写锁,公平/非公平锁,票据锁(1.8)。大家有空可以看下票据锁,这里有一篇各种锁的性能测试blog,感兴趣的可以看下。
看了上面的这么多blog,你是否发现了各种锁他们都有共同的特点,都有一个监视器(控制资源,防止多个线程使用),一个或多个等待队列(存储那些获取失败且且需要等待的线程),一个唤醒器(资源没被利用时,唤醒等待队列的线程进行资源争夺)。他们的实现逻辑也大致相同,首先给资源加上监视器,线程进来后判断线程是否符合条件,符合得到线程的使用权,不符合加入到等待队列。资源释放后,唤醒器唤醒等待队列中的线程进行下一轮的资源抢夺。这个是单个应用下的锁是这么实现的,那多个应用的锁是否也是这么实现的呢?
现在分布式锁实现方式大致是三种:基于数据库实现分布式锁,基于缓存实现分布式锁,基于Zookeeper实现分布式锁 。详情可以参考blog。
通过上面的阅读,或者你对分布式锁的了解,我们会发现分布式锁和我们平常用到的java锁逻辑上没有什么大的区别。区别只不过是线程变成了进程或不同进程下的线程,监视器由代码实现的监视器(synchronized 监视器由jvm底层源码实现)变成了具体的工具(数据库,缓存器,Zookeeper)。唤醒器 数据库和缓存 实现方式用while(true)方式实现 不用唤醒线程 会一直检测自身是否符合条件 ;Zookeeper则通过watch机制来实现。等待队列数据库和缓存 实现方式没有把竞争失败的存储起来,而是不停的检测自身是否能通过监视器 ;Zookeeper则通过自身的临时有序节点来存储。
看到这里,可以发现分布式锁也没有那么神秘,其实和我们平常用的锁原理是一样的,只是实现方式不同而已。
现在技术创新层出不穷,我们看的眼花缭乱。究其本质,又有多少技术是真的是新的呢。
特别感谢一下大佬提供的blog:
https://baijiahao.baidu.com/s?id=1580364922566928882&wfr=spider&for=pc
https://blog.csdn.net/hello_worldee/article/details/77843858
https://blog.csdn.net/yanyan19880509/article/details/52435135
https://blog.csdn.net/zhaopengnju/article/details/51830234
https://www.cnblogs.com/huangjuncong/p/9191760.html
http://www.importnew.com/19981.html
http://www.cnblogs.com/austinspark-jessylu/p/8043726.html