synchronized原理详解
synchronized内置锁是一种对象锁(锁的是对象而非引用),作用粒度是对象,可以用来实现对临界资源的同步互斥访问,是可重入的。
加锁的方式:
1、同步实例方法,锁是当前实例对象
2、同步类方法,锁是当前类对象
更细粒度
3、同步代码块,锁是括号里面的对象
加在类对象上面,需要注意,会导致整个性能瓶颈都在这里
synchronized底层原理
synchronized是基于JVM内置锁实现,通过内部对象Monitor(监视器锁)实现,基于进入与退出Monitor对象实现方法与代码块同步,监视器锁的实现依赖底层操作系统的Mutex lock(互斥锁)实现,它是一个重量级锁性能较低。
当然,JVM内置锁在1.5之后版本做了重大的优化,如锁粗化(Lock Coarsening)、锁消除(Lock Elimination)、轻量级锁(Lightweight Locking)、偏向锁(Biased Locking)、适应性自旋(Adaptive Spinning)等技术来减少锁操作的开销,,内置锁的并发性能已经基本与Lock持平。
synchronized关键字被编译成字节码后会被翻译成monitorenter 和 monitorexit
指令进入前后会有监控.

HotSpot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。
对象头:比如 hash码,对象所属的年代,对象锁,锁状态标志,偏向锁(线程)ID,偏向时间,数组长度(数组对象)等。Java对象头一般占有2个机器码(在32位虚拟机中,1个机器码等于4字节,也就是32bit,在64位虚拟机中,1个机器码是8个字节,也就是64bit),但是 如果对象是数组类型,则需要3个机器码,因为JVM虚拟机可以通过Java对象的元数据信息确定Java对象的大小,但是无法从数组的元数据来确认数组的大小,所以用一块来记录数组长度。
-
Synchronized锁升级:
Screen Shot 2022-04-06 at 10.23.48 PM.png
对象头可以用ClassLayout工具打印出来.
无锁
偏向锁(默认延迟开启) MarkWord替换
轻量级锁 CAS 操作,自旋
重量级锁 用户态内核态
- markword标志位:

对象头,hashcode,分带年龄,锁标志位. 如图所示.
java c ,javap -c l- xxx.class文件可以查看字节码文件信息.
public static void main(java.lang.String[]);
Code:
0: aload_0
1: dup
2: astore_1
3: monitorenter
4: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
7: ldc #3 // String aaa
9: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
12: aload_1
13: monitorexit
14: goto 22
17: astore_2
18: aload_1
19: monitorexit
20: aload_2
21: athrow
22: return
public static void main(String[] args) {
synchronized (args){
System.out.println("aaa");
}
}
monitor指令会有监视器监控该段代码,在执行和退出的时候均会执行该操作.
该指令相当于对象访问的钥匙,只有拿到该对象的monitor才能访问。类似
进入则线程数量设置成1,运行完后出了代码块,monitor数量减一.
- 逃逸分析复习:
- for循环超过一千次
- 开启了 -XX: +DOEscapeAnalysis 逃逸分析
对象返回值在栈上被引用了.
- 补充:
锁粗化
比如Stringbuffer的append方法会加锁.
连续调用的时候可以将锁的范围做放大,放大到调用的更广级别.
锁消除:
JIT编译器发现在编译时期,扫描上下文发现不可能存在共享资源竞争的情况,就会必要消除没有必要的锁.
锁消除:
-XX: +DoEscapeAnalysis
-XX:+EliminateLocks 表示开启锁消除。
另外逃逸分析为锁消除提供了支持
对象头内存布局
哈希码,GC分代年龄,锁标志位,持有的锁,线程ID,时间戳等.
java.lang.String object internals:
OFF SZ TYPE DESCRIPTION VALUE
0 8 (object header: mark) 0x0000700007d1ca30 (thin lock: 0x0000700007d1ca30)
8 4 (object header: class) 0x00061cca
12 4 byte[] String.value []
16 4 int String.hash 0
20 1 byte String.coder 0
21 1 boolean String.hashIsZero true
22 2 (object alignment gap)
Instance size: 24 bytes
Space losses: 0 bytes internal + 2 bytes external = 2 bytes total
网友评论