美文网首页
Day26 Synchronized

Day26 Synchronized

作者: 小周爱吃瓜 | 来源:发表于2022-04-06 22:25 被阅读0次

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
指令进入前后会有监控.

Screen Shot 2022-04-06 at 10.23.05 PM.png

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标志位:
Screen Shot 2022-04-07 at 11.52.32 PM.png

对象头,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数量减一.


  • 逃逸分析复习:
  1. for循环超过一千次
  2. 开启了 -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

相关文章

网友评论

      本文标题:Day26 Synchronized

      本文链接:https://www.haomeiwen.com/subject/hwvdsrtx.html