Synchronized
Synchronized基本描述
·对于普通同步方法,锁是当前实例对象。
·对于静态同步方法,锁是当前类的Class对象。
·对于同步方法块,锁是Synchonized括号里配置的对象。
JVM基于进入和退出Monitor对象来实现方法同步和代码块同步,但两者的实现细节不一样。代码块同步是使用monitorenter和monitorexit指令实现的,而方法同步是使用另外一种方式实现的,synchronized 修饰的方法并没有 monitorenter 指令和 monitorexit 指令,取得代之的是 ACC_SYNCHRONIZED 标识
monitorenter指令是在编译后插入到同步代码块的开始位置,而monitorexit是插入到方法结束处和异常处
任何对象都有一个monitor与之关联,当一个monitor被持有后,它将处于锁定状态。线程执行到monitorenter指令时,将会尝试获取对象所对应的monitor的所有权,即尝试获得对象的锁。
// 锁方法
public synchronized void add(){
i++;
}
public synchronized void add();
descriptor: ()V
flags: (0x0021) ACC_PUBLIC, ACC_SYNCHRONIZED
Code:
stack=3, locals=1, args_size=1
0: aload_0
1: dup
2: getfield #2 // Field i:I
5: iconst_1
6: iadd
7: putfield #2 // Field i:I
10: return
// 锁代码块
public void add() {
synchronized (this) {
i++;
}
}
public void add();
Code:
0: aload_0
1: dup
2: astore_1
3: monitorenter // synchronized关键字的入口
4: getstatic #2 // Field i:I
7: iconst_1
8: iadd
9: putstatic #2 // Field i:I
12: aload_1
13: monitorexit // 正常程序执行synchronized关键字的出口
14: goto 22
17: astore_2
18: aload_1
19: monitorexit // 抛异常时synchronized关键字的出口
20: aload_2
21: athrow
22: return
Java对象头
synchronized用的锁是存在Java对象头里的
不同类型对象,对象头的字宽说明,在32位虚拟机中,1字宽等于4字节,即32bit
- 数组类型:3字宽
- 非数组:2字宽
对象头组成

- Mark Word(1字宽)
- 对象数据类型指针(1字宽)
- 数组长度(这就是数据多的一个字宽的用处)
Mark Word
无锁状态

运行期间

口诀:25+4+1+2,2️⃣ 5️⃣法则:2锁,5针
口诀:00轻、10重、11GC、01偏
特殊案例分析
1.synchronized(this),锁的对象是this,是类的实例。
2.synchronized(object),锁的对象是object。
class STest{
public void print(){
synchronized (this){
System.out.println("xxxx");
}
}
}
public class SynchronizeMain {
public static void main(String[] args) throws InterruptedException {
STest sTest = new STest();
// Thread 1
Thread t1 = new Thread(() -> {
sTest.print();
});
// Thread 2
Thread t2 = new Thread(() -> {
try {
synchronized (sTest){
while (true);
}
} catch (Exception e) {
System.out.println("Exception="+e.getMessage());
}
});
// 抢占了 sTest 锁,属于同步块锁,锁的是 sTest 对象
t2.start();
// sTest.print()永远无法执行
t1.start();
}
}
如果第一种方式用锁,如果使用这种方式,一旦锁对象(实例)被别人获取,那么线程将会被挂起,这就是说,当实例方法被别的线程锁住,就有可能造成正常锁代码块无法执行。
如果第二种方式用锁,除非都调用方法块内的方法,否则互不影响。

浙公网安备 33010602011771号