Synchronized注意事项

Table of Contents

1.概述

1.1实现方式

1.2使用方式

2.对象内部结构

2.1对象内部结构

2.2  Mark Word 在 32 位 JVM 中存储内容  

2.3 Mark Word 在 64 位 JVM 中存储内容   [ 待考证 ]  

3.锁升级过程

4. 什么时候用自旋锁什么时候用系统锁?

5. 为什么Synchronized不能加在String和Integer等基本包装类型上


1.概述

1.1实现方式

synchronized 是 JVM 内置锁,通过内部对象 Monitor(监视器锁)实现,基于进入与退出 Monitor 对象实现方法与代码块同步,监视器锁的实现依赖底层操作系统的 Mutex lock (互斥锁)实现

 

1.2使用方式

1.同步实例方法,锁是当前实例对象

2.同步类方法.锁是当前类对象

3.同步代码块,锁是括号里面的对象

 

 

2.对象内部结构

2.1对象内部结构

Synchronized注意事项

2.2  Mark Word 在 32 位 JVM 中存储内容  

Synchronized注意事项

 

2.3 Mark Word 在 64 位 JVM 中存储内容   [ 待考证 ]  

Synchronized注意事项

 

3.锁升级过程

无锁->偏向锁->轻量级锁->重量级锁    [ 整个过程不可逆!!!! ]

Synchronized注意事项

 

4. 什么时候用自旋锁什么时候用系统锁?

自旋锁: 执行时间短 且 线程数少  .

系统锁: 执行时间长 或者 线程多. 

 

5. 为什么Synchronized不能加在String和Integer等基本包装类型上

 

同步块不应该加在String或基本包装类型上,如Byte、Short、Integer、Long、Float、Double、Boolean、Character。

String不能用作同步块的参数是因为String为不可变对象,任何String对象的改变都将产生一个新的String对象,这也将导致前面加的锁不会被释放,或者因为String对象改变,其他线程拿到锁影响到上一个正在拿着锁执行任务的程序.

Integer、Boolean、Double、Long不能作为同步块参数的原因是他们是基本包装类型,包装类型有特殊的逻辑,用一句话说就是Java的自动封箱和解箱操作会导致这些对象在经过运算后不再是原来的对象

用复杂的话说就是:当把基本变量赋值给包装类型的变量(其实编译过后的操作就是调用包装类型的静态方法valueOf)或者调用静态valueOf方法时:

  • Boolean返回的是缓存的对象。
  • 整型(Byte,Short,Integer,Long)会检查该数字是否在1个字节可表示的有符号整数范围内(-128~127),是则返回缓存对象,否则返回新对象。
  • Character会缓存整型值为0~127的字符,同样会检查字符是否落在缓存范围中,是则返回,否则返回新对象。
  • Double和Float的valueOf方法始终返回新对象。