1.概要总结
1.1. 大纲总结
出现线程安全性问题的条件
在多线程的环境下
必须有共享资源
对共享资源进行非原子性操作
解决线程安全性问题的途径
synchronized (偏向锁,轻量级锁,重量级锁)
volatile
JDK提供的原子类
使用Lock(共享锁,排它锁)
1.2. 线程总结
- 出现线程安全性问题的条件
-
- 在多线程的环境下
-
- 必须有共享资源
-
- 对共享资源进行非原子性操作
- 解决线程安全性问题的途径
-
- synchronized JDK6升级后(偏向锁,轻量级锁,重量级锁)
-
- volatile 线程可见,保证读写可见,不保证原子性
-
- JDK提供的原子类
-
- 使用Lock(共享锁,排它锁),AQS,ReentrantLock,ReReadWriteLock–
-
- 单例模式及双重检查,模板方法模式
- 认识的“*锁”
-
- 偏向锁
-
- 轻量级锁
-
- 重量级锁
-
- 重入锁
-
- 自旋锁
-
- 共享锁
-
- 独占锁
-
- 排他锁(互斥锁)
-
- 读写锁
-
- 公平锁
-
- 公平/非公平锁
-
- 死锁
-
- 活锁
-
- 内置锁
2.锁
2.1 锁原理
任何对象都可以作为锁,那么锁信息又存在对象的什么地方呢? ==> 存在对象头中
对象头中的信息有:
-
Mark Word(锁相关信息在这里,几种类型标志位,不同标志位不同信息)
-
- 线程id
-
- Epoch
-
- 对象的分代年龄信息
-
- 是否是偏向锁
-
- 锁标志位
-
-
Class Metadata
-
Address
-
Array Length
-
JVM规范规定JVM基于进入和退出Monitor对象来实现方法同步和代码块同步,但两者的实现细节不一样。
-
代码块同步是使用monitorenter和monitorexit指令实现,而方法同步是使用另外一种方式实现的,细节在JVM规范里并没有详细说明,但是方法的同步同样可以使用这两个指令来实现。
-
monitorenter指令是在编译后插入到同步代码块的开始位置,而monitorexit是插入到方法结束处和异常处, JVM要保证每个monitorenter必须有对应的monitorexit与之配对。任何对象都有一个 monitor 与之关联,当且一个monitor 被持有后,它将处于锁定状态。线程执行到 monitorenter 指令时,将会尝试获取对象所对应的 monitor 的所有权,即尝试获得对象的锁。