美文网首页
synchronized底层实现

synchronized底层实现

作者: 叫我C30混凝土 | 来源:发表于2020-11-08 23:54 被阅读0次

synchronized

  • java语言级的支持,1.6之后性能极大提高
  • 字节码层面的实现: monitorenter/monitorexit
//代码
private void increment(){ 
        synchronized(this){
            counter++;
        }
    }

//字节码
private increment()V
    TRYCATCHBLOCK L0 L1 L2 null
    TRYCATCHBLOCK L2 L3 L2 null
   L4
    LINENUMBER 22 L4
    ALOAD 0
    DUP
    ASTORE 1
    MONITORENTER //占有锁(监视器)
   L0
    LINENUMBER 23 L0
    ALOAD 0
    GETFIELD com/Coordinator$MyThread.i : Ljava/lang/Integer;
    ASTORE 2
    ALOAD 0
    ALOAD 0
    GETFIELD com/Coordinator$MyThread.i : Ljava/lang/Integer;
    INVOKEVIRTUAL java/lang/Integer.intValue ()I
    ICONST_1
    IADD
    INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer;
    DUP_X1
    PUTFIELD com/Coordinator$MyThread.i : Ljava/lang/Integer;
    ASTORE 3
    ALOAD 2
    POP
   L5
    LINENUMBER 24 L5
    ALOAD 1
    MONITOREXIT  // 退出锁(监视器)
   L1
    GOTO L6
   L2
   FRAME FULL [com/Coordinator$MyThread java/lang/Object] [java/lang/Throwable]
    ASTORE 4
    ALOAD 1
    MONITOREXIT
   L3
    ALOAD 4
    ATHROW
   L6
    LINENUMBER 25 L6
   FRAME CHOP 1
    RETURN
   L7
    LOCALVARIABLE this Lcom/Coordinator$MyThread; L4 L7 0
    MAXSTACK = 3
    MAXLOCALS = 5

//方法2.synchronized 在方法上
private synchronized static void doSomething(){
            i++;
        }

  • 锁住的是什么?
    - 在方法中时,锁住的是其中的对象 ;
    - 在方法上时,1. static方法锁住的是当前的class对象;2. 非static方法,锁住的是当前对象的实例;
// 反例:
static class MyThread extends Thread{
        private synchronized void doSomething(){

        }
        @Override
        public void run(){
            doSomething();
            System.out.println(123);
        }
    }

    public static void main(String[] args) {
        // 开启了四个线程,但synchronized 方法锁住的是每个实例自己的doSomething();所以synchronized 锁并没有用;
        new MyThread().start();
        new MyThread().start();
        new MyThread().start();
        new MyThread().start();
    }
  • 底层实现
    - 对象头
    - 无锁 -> 偏向锁(biased lock) -(锁膨胀)> 轻量级锁 -(锁膨胀)> 重量级锁
    无锁状态: 没有线程访问,是个游离在JVM中的对象;
    偏向锁状态: 一直以来都是同一个线程访问,该对象头会变成偏向锁,下次该线程访问,可以直接使用;此时没有锁发生,所以即使线程不再调用,标志位还会一直存在在对象头中;
    当第二个线程,尝试获取该锁,偏向锁标志位会撤销,会恢复成无锁的状态;
    轻量级锁状态: 有线程竞争的情况发生,但是不严重(同一时刻只有一个线程获取锁),假如能抢到我的话,就不需要获取monitor.
    重量级锁状态: 有多个线程在竞争锁,所以必须获取monitor;

              所以进入monitorenter时,或退出monitorexit时,不一定需要获取monitorenter或释放monitorexit;
    
        对象头定义: markOop.hpp
        锁膨胀定义: synchronizer.cpp
    
对象头.png

锁粗化与锁消除

  • 锁粗化: 同一个锁要连续频繁加锁解锁,粗化为更大范围的锁;
public static void main(String[] args) {
        increment();
    }

    private static void increment(){
        // monitorenter
        for (int i = 0 ;i <10; i++) {
            foo();
        }
         // monitorexit
    }

    // foo()频繁的加锁解锁,编译器就会把他优化成更大范围的锁
    private static synchronized void foo() {
        System.out.println("");
    }
  • 锁消除: 不可能有人和我竞争锁,所以没必要上锁;

相关文章

网友评论

      本文标题:synchronized底层实现

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