java-锁01

Synchronized

锁的是对象不是代码块,当线程获取到锁对象时才能够正常运行

    普通同步方法,锁是当前实例对象。

    静态同步方法,锁是当前类的 class 对象。

    同步方法块,锁是括号里面的对象。


synchronized 实现细节

图一

1)字节码层面:同步代码块主要有monitorenter和monitorexit指令来实现锁获取和锁释放。

2)字节码层面:字节码层面同步方法是由ACC_SYNCHRONIZED关键字标识的。

3)JVM层面:C C++ 调用了操作系统提供的同步机制 。(总线锁lock、缓存一致性协议)

在jvm底层synchronized是由对象头和monitor实现的。

对象头

    Hotspot 虚拟机的对象头主要包括两部分数据:Mark Word(标记字段)、Klass Pointer(类型指针)

    Klass Pointer 是对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。

    Mark Word    用于存储对象自身的运行时数据,如哈希码(HashCode)、GC 分代年龄、锁状态标志(有2bit 如:01无锁、00 轻量级锁 等)、线程持有的锁、偏向线程 ID等。

Monitor

    是一种同步机制,把它理解成一个对象。

    互斥:一个 Monitor 锁在同一时刻只能被一个线程占用,其他线程无法占用。                  信号机制:占用 Monitor 锁失败的线程会暂时放弃竞争并等待条件变量成真,但该条件成立后,当前线程会 通过释放锁通知正在等待这个条件变量的其他线程,让其可以重新竞争锁。    

    属性:Owner: 1)初始时为 NULL 表示当前没有任何线程拥有该 Monitor Record;2)当线程成功拥有该锁后保存线程唯一标识;3)当锁被释放时又设置为 NULL 。EntryQ:关联一个系统互斥锁( semaphore ),阻塞所有试图锁住 Monitor Record失败的线程 。RcThis: 表示 blocked 或 waiting 在该 Monitor Record 上的所有线程的个数。Nest:用来实现重入锁的计数。HashCode: 保存从对象头拷贝过来的 HashCode 值(可能还包含 GC age )。Candidate:用来避免不必要的阻塞或等待线程唤醒。因为每一次只有一个线程能够成功拥有锁,如果每次前一个释放锁的线程唤醒所有正在阻塞或等待的线程,会引起不必要的上下文切换(从阻塞到就绪然后因为竞争锁失败又被阻塞)从而导致性能严重下降。Candidate 只有两种可能的值 :1)0 表示没有需要唤醒的线程;2)1 表示要唤醒一个继任线程来竞争锁。


synchronized升级

synchronized 是重量级锁,效率比较低。在jdk1.6后对它进行了升级。

偏向锁--> 自旋锁 --->重量级锁(锁升级只能从轻往重升级,不能反过来)

偏向锁:当使用synchronized锁住那个对象时,会把该线程id设置上去,与下次获取该锁的线程做对比,如果仍然是该线程便不用进行所释放。

自旋锁:使用cpu的特性让线程循环获取锁。循环到获取到锁为止。(可以手动设置自旋次数)

重量级锁:使用jvm特性去获取、释放os。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。