java重点学习-线程的并发安全(2)
九 线程的并发安全
9.7 ReentrantLock的实现原理
- ReentrantLock表示支持重新进入的锁,调用lock方法获取了锁之后,再次调用 lock,是不会再阻塞
- ReentrantLock主要利用CAS+AQS队列来实现
- 支持公平锁和非公平锁,在提供的构造器的中无参默认是非公平锁,也可以传参设置为公平锁
9.8 synchronized和Lock有什么区别?
语法层面
- synchronized 是关键字,源码在jvm 中,用 c++语言实现
- Lock 是接口,源码由jdk 提供,用java 语言实现
- 使用 synchronized 时,退出同步代码块锁会自动释放,而使用 Lock 时,需要手动调用 unlock 方法释放锁
功能层面
- 二者均属于悲观锁、都具备基本的互斥、同步、锁重入功能
- Lock 提供了许多 synchronized 不具备的功能,例如公平锁、可打断、可超时、多条件变量
- Lock 有适合不同场景的实现,如 ReentrantLock,ReentrantReadWriteLock(读写锁)
性能层面
- 在没有竞争时,synchronized 做了很多优化,如偏向锁、轻量级锁,性能不赖
- 在竞争激烈时,Lock 的实现通常会提供更好的性能
可打断
锁超时
9.9 死锁产生的条件和解决方式
1.死锁产生的条件是什么?
一个线程需要同时获取多把锁,这时就容易发生死锁
2.如何进行死锁诊断?
- 当程序出现了死锁现象,我们可以使用jdk自带的工具:jps和jstack
- jps:输出JVM中运行的进程状态信息
- jstack:查看java进程内线程的堆栈信息,查看日志,检查是否有死锁如果有死锁现象,需要查看具体代码分析后,
- 可修复可视化工具jconsole、VisualVM也可以检查死锁问题
死锁的诊断
9.10 聊-下ConcurrentHashMap
1.底层数据结构:
JDK1.7底层采用分段的数组+链表实现
JDK1.8 采用的数据结构跟HashMap1.8的结构一样,数组+链表/红黑二叉树
2.加锁的方式
JDK1.7采用Segment分段锁,底层使用的是ReentrantLock
JDK1.8采用CAS添加新节点,采用synchronized锁定链表或红黑二叉树的首节点,相对Segment分段锁粒度更细,性能更好
9.11 导致并发程序出现问题的根本原因是什么
(Java程序中怎么保证多线程的执行安全)
- 1.原子性synchronized、lock
- 2.内存可见性 volatile、synchronized、lock
- 3.有序性volatile