Java中的21种锁,图文并茂的详细解释

作者:悟空聊架构

Java中的21种锁,图文并茂的详细解释

文章插图
 
本篇主要内容如下:
Java中的21种锁,图文并茂的详细解释

文章插图
 
本篇主要内容
本篇文章已收纳到我的JAVA在线文档、 Github
我的SpringCloud实战项目持续更新中
帮你总结好的锁:
序号锁名称应用1乐观锁CAS2悲观锁synchronized、vector、hashtable3自旋锁CAS4可重入锁synchronized、Reentrantlock、Lock5读写锁ReentrantReadWriteLock , CopyOnWriteArrayList、CopyOnWriteArraySet6公平锁Reentrantlock(true)7非公平锁synchronized、reentrantlock(false)8共享锁ReentrantReadWriteLock中读锁9独占锁synchronized、vector、hashtable、ReentrantReadWriteLock中写锁10重量级锁synchronized11轻量级锁锁优化技术12偏向锁锁优化技术13分段锁concurrentHashMap14互斥锁synchronized15同步锁synchronized16死锁相互请求对方的资源17锁粗化锁优化技术18锁消除锁优化技术
1、乐观锁
Java中的21种锁,图文并茂的详细解释

文章插图
 
乐观锁
乐观锁是一种乐观思想 , 假定当前环境是读多写少 , 遇到并发写的概率比较低 , 读数据时认为别的线程不会正在进行修改(所以没有上锁) 。写数据时 , 判断当前 与期望值是否相同 , 如果相同则进行更新(更新期间加锁 , 保证是原子性的) 。
Java中的乐观锁: CAS , 比较并替换 , 比较当前值(主内存中的值) , 与预期值(当前线程中的值 , 主内存中值的一份拷贝)是否一样 , 一样则更新 , 否则继续进行CAS操作 。
如上图所示 , 可以同时进行读操作 , 读的时候其他线程不能进行写操作 。
2、悲观锁 
Java中的21种锁,图文并茂的详细解释

文章插图
 
悲观锁
悲观锁是一种悲观思想 , 即认为写多读少 , 遇到并发写的可能性高 , 每次去拿数据的时候都认为其他线程会修改 , 所以每次读写数据都会认为其他线程会修改 , 所以每次读写数据时都会上锁 。其他线程想要读写这个数据时 , 会被这个线程block , 直到这个线程释放锁然后其他线程获取到锁 。
Java中的悲观锁: synchronized修饰的方法和方法块、ReentrantLock 。
如上图所示 , 只能有一个线程进行读操作或者写操作 , 其他线程的读写操作均不能进行 。
3、自旋锁 
Java中的21种锁,图文并茂的详细解释

文章插图
 
自旋锁是一种技术: 为了让线程等待 , 我们只须让线程执行一个忙循环(自旋) 。
现在绝大多数的个人电脑和服务器都是多路(核)处理器系统 , 如果物理机器有一个以上的处理器或者处理器核心 , 能让两个或以上的线程同时并行执行 , 就可以让后面请求锁的那个线程“稍等一会” , 但不放弃处理器的执行时间 , 看看持有锁的线程是否很快就会释放锁 。
自旋锁的优点: 避免了线程切换的开销 。挂起线程和恢复线程的操作都需要转入内核态中完成 , 这些操作给Java虚拟机的并发性能带来了很大的压力 。
自旋锁的缺点: 占用处理器的时间 , 如果占用的时间很长 , 会白白消耗处理器资源 , 而不会做任何有价值的工作 , 带来性能的浪费 。因此自旋等待的时间必须有一定的限度 , 如果自旋超过了限定的次数仍然没有成功获得锁 , 就应当使用传统的方式去挂起线程 。
自旋次数默认值:10次 , 可以使用参数-XX:PreBlockSpin来自行更改 。
自适应自旋: 自适应意味着自旋的时间不再是固定的 , 而是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定的 。有了自适应自旋 , 随着程序运行时间的增长及性能监控信息的不断完善 , 虚拟机对程序锁的状态预测就会越来越精准 。
Java中的自旋锁: CAS操作中的比较操作失败后的自旋等待 。
4、可重入锁(递归锁)可重入锁
可重入锁是一种技术: 任意线程在获取到锁之后能够再次获取该锁而不会被锁所阻塞 。
可重入锁的原理: 通过组合自定义同步器来实现锁的获取与释放 。


推荐阅读