synchronized
1. synchronized锁在静态方法和非静态方法中的差异
- synchronized在静态方法中锁的是当前类的.class对象
- synchronized在非静态方法锁的是当前类的实例对象
- synchronized在代码块中锁的是括号中的的对象
2. synchronized锁的优化
JDK1.6对synchronized进行的优化,主要在三个方面
- 锁消除
在synchronized修饰的代码块中,如果不存在操作临界资源的情况,触发锁消除,即synchronized无效。
- 锁膨胀
如果在一个循环内部使用synchronized,频繁的获取/释放锁消耗资源。锁膨胀就是将synchronized放到循环体外部,这样就获取/释放一次锁。
public class Test01 {
public static void main(String[] args) {
//之前代码
for (int i = 0; i < 100; i++) {
synchronized (Test01.class){
}
}
//膨胀后
synchronized (Test01.class){
for (int i = 0; i < 100; i++) {
}
}
}
}
- 锁升级
在jdk1.6之前,线程在获取不到锁后,立即挂起线程。优化之后分为四种锁状态:
- 无锁/匿名偏向状态:当前对象没有作为锁存在。
- 偏向锁:如果当前资源只有一个线程在频繁的获取和释放,那么这个线程在获取锁的时候只需要判断当前锁对象指向的线程是否是频繁获取锁的那个线程,如果是,直接获取锁。如果出现其它线程竞争,那么另一个线程尝试CAS获取锁,如果获取不到,触发锁升级。升级为轻量级锁
- 轻量级锁:采用自适应自旋锁以CAS的方式获取锁,如果达到自适应次数没有获取锁,触发锁升级,升级为重量级锁。
- 重量级锁:传统的synchronized方式,拿不到锁,线程挂起。
3.synchronized原理
在创建对象作为锁的时候,会在栈中生成对象的引用,引用指向堆空间,有关锁的内容存储在对象的对象头中的MarkWord中。
HotSpot中的MarkWord
- 图中黄色部分是锁的标志位:
- 001:无锁状态/匿名偏向锁状态,其中0标识偏向锁位,偏向与null
- 101:偏向锁状态,其中1表示偏向某个对象
- 00:轻量级锁状态,其中lock Record指针指向栈中持有锁的线程
- 10:重量级锁状态,其中lock Record指针指向Object Monitor
锁升级的过程
Object Monitor :
可以理解为一个临界资源,在同一时间只能有一个线程操作它,实现线程之间互斥的效果。Object Monitor是基于C++实现的。