基本使用
- synchronized放在实例方法上,锁对象是当前的this对象
- synchronized放在类方法(静态方法)上,锁对象是方法区中的类对象
- synchronized修饰代码块,也就是synchronized(object){},锁对象是()中的对象
synchronized用来修饰方法时,是通过ACC_SYNCHRONIZED标识符来保持线程同步的。
synchronized用来修饰代码块时,是通过monitorenter和monitorexit指令来完成
实现原理
-  代码层面, Synchronized 关键字。 
-  JAVA 字节码层面,同步方法是 ACC_SYNCHRONIZED 修饰的方法定义,同步代码块使用 monitorenter和monitorexit两个指令实现。 
-  JVM 层面, 无锁,偏向锁,轻量级锁,重量级锁。 
-  操作系统层面是调用了汇编指令 lock cmpxchg,通过 lock 保证后面的命令(cmpxchg)只能一个线程执行。 
-  硬件层面,是锁住了一个北桥的信号量。 
1) CPMXCHG
- 用于比较并交换操作数,CPU对CAS的原语支持
- 非原子性,最早用于单核CPU
2) LOCK前缀
-  CPU保证被其修饰的指令的原子性 
-  禁止重排序 
-  缓存刷新到内存 
借助什么来实现?
1. 对象头中的Mark Word
偏向锁
if (锁的标记位 == 01) {
    if (偏向标记是1){
        是偏向锁且可偏向
        boolean CAS操作结果 = CAS操作替换偏向线程的ID为当前线程
        if ( CAS操作结果 == 成功){
            当前线程获得锁
            执行同步代码块
        } else {
            CAS操作失败
            开始【偏向锁的撤销】{
                等到全局安全点
                var 状态 = 检查原来持有锁的线程的状态
                if (状态 == terminated || 已经退出同步代码区)
                    原线程释放锁
                    当前线程获得锁
                else if (状态 == runnable && 未退出同步代码区){
                    执行【偏向锁膨胀到轻量级锁】的过程{
                        原持有锁的线程栈幁分配锁记录、替换MarkWord并指向对象地址、执行同步代码块、CAS操作释放锁
                        当前线程执行轻量级锁的抢锁过程{
                            CAS自旋
                            if (自旋一定次数还没有获取锁){
                                膨胀到重量级锁
                            }
                        }
                    }
                }
            }
        }
    }else {
        goto line 4 执行CAS操作
    }
}else {
    不是偏向锁
}
复制代码轻量级锁
if (锁的标记位 == 00) {
    是轻量级锁
    执行轻量级锁的抢占{
        当前线程的栈幁中 分配 【锁记录】,【锁记录】由两个部分构成,【displaced Markword】 和 【onwer指针】
        把锁对象的【对象头】中的【Markword】拷贝到锁记录中的【displaced Markword】中
        onwer指针 指向 该锁对象
        CAS修改锁对象的对象头,使其中的【指向线程锁记录的指针】 这一字段指向当前线程
        if (CAS操作成功){
            当前线程持有锁
        }else{
            CAS操作失败
            CAS自旋
            if (自旋超过一定次数还没有成功){
                升级为重量级锁{
                    改变Markword
                    挂起当前线程
                }
            }
        }
    }
    }else {
    不是轻量级锁
}
复制代码2. Monitor监视器对象
Java中,每个对象里面隐式的存在一个叫monitor(对象监视器)的对象,Monitor监视器对象存在于Java对象的对象头Mark Word中,这个对象源码是采用C++实现的
 class ObjectMonitor {
...
  ObjectMonitor() {
    _header       = NULL; //markOop object header
    _count        = 0;    
    _waiters      = 0,   //Number of waiting threads
    _recursions   = 0;   //Thread reentry times
    _object       = NULL;  //Store Monitor object
    _owner        = NULL;  //Thread to get ObjectMonitor object
    _WaitSet      = NULL;  //List of threads in wait state
    _WaitSetLock  = 0 ; 
    _Responsible  = NULL ;
    _succ         = NULL ;
    _cxq          = NULL ;	// One way list
    FreeNext      = NULL ;
    _EntryList    = NULL ; //Thread waiting for lock BLOCKED
    _SpinFreq     = 0 ;   
    _SpinClock    = 0 ;
    OwnerIsThread = 0 ; 
    _previous_owner_tid = 0; //ID of the previous owning thread of the monitor
  }
...
复制代码流程
感谢:Jacksgong
锁重入
-  偏向锁的锁重入 - 简单判断mark word中的偏向线程ID
 
-  轻量级锁的锁重入 -  再次放入锁记录, 只不过displaed markword为null 
-  通过锁记录的个数判断重入的次数 
-  在高位的是第一次的锁记录 
 
-  
-  重量级锁的锁重入 -  操作系统来实现 
 
-  
原文链接:https://juejin.cn/post/7049292731109081119
如果你觉的本文对你有帮助,麻烦点赞关注支持一下

 京公网安备 11010502036488号
京公网安备 11010502036488号