当前位置:网站首页>Synchronization lock synchronized traces the source

Synchronization lock synchronized traces the source

2022-08-09 23:12:00 Learned Valley Wild Architects

1 同步锁synchronized追本溯源

引言
提到synchronized,Both in the development process and the interview process often encountered problems
synchronized;It is also a disaster area

Why is it said to be the hardest hit area?
Because he is not like other codes,There is source code,可以查看的
synchronized是一个关键字.Can't find the source code directly

接下来
我们会通过javaMemory script and c++源码(HotSpot虚拟机源码)
Let us analyze itsynchronizedIn the end is how to achieve lock synchronization

1.1 synchronized场景回顾

目标:

synchronized回顾

概念

**synchronized:**是Java中的关键字,是一种同步锁.

synWhich lock category does it belong to:

  • 乐观锁、悲观锁(syn)

  • 独享锁(syn)、共享锁

  • 公平锁、非公平锁(syn)

  • 互斥锁(syn)、读写锁

  • 可重入锁(syn)

tips:

synchronized JDK1.6锁升级 : 无锁 -> 偏向锁 (非锁)-> 轻量级锁 -> 重量级锁(1.6前都是)

多线程特性回顾(面试常问)

原子性:指一个操作或者多个操作,要么全部执行并且执行的过程不会被任何因素打断,要么就都不执行

**可见性:**是指多个线程访问一个资源时,该资源的状态、值信息等对于其他线程都是可见的.

**有序性:**指程序中代码的执行顺序 (编译器会重排)

syncThe above three features can be fully implemented to ensure thread safety,casatomicity cannot be achieved.

这是什么原理呢?

1.2 反汇编寻找锁实现原理

目标

通过javap反汇编看一下synchronized到底是怎么加锁的

com.syn.BTest

public class BTest {
    
    private static Object object = new Object();

     public synchronized void testMethod() {
    
        System.out.println("Hello World -synchronized method ");
    }

    public static void main(String[] args) {
    
        synchronized (object) {
    
            System.out.println("Hello World -synchronized block ");
            
        }
    }
}

反汇编后,我们将到什么?

file

JDK自带的一个工具: javap ,对字节码进行反汇编:

//com.syn.BTest 
javap -v -c BTest.class

-v:输出附加信息

-c:对代码进行反汇编

反汇编后

file

解释
被synchronized修饰的代码块,多了两个指令
monitorenter、monitorexit
即JVM使用monitorenter和monitorexit两个指令实现同步

file

解释

The method is checked when the method is called ACC_SYNCHRONIZED 访问标志是否被设置,如果设置了,执行线程将先获取monitor,获取成功之后才能执行方法体,方法执行完后再释放monitor.也就是jvm会隐式调用monitorenter和
monitorexit.

  • monitorenter原理

monitorenter首先我们来看一下JVM规范中对于monitorenter的描述

https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.monitorenter
monitorenter :
Each object is associated with a monitor. A monitor is locked if and only if it has an owner. The thread that executes monitorenter attempts to gain ownership of the monitor associated with objectref, as follows:
• If the entry count of the monitor associated with objectref is zero, the thread enters the monitor and sets its entry count to one. The thread is then the owner of the monitor.
• If the thread already owns the monitor associated with objectref, it reenters the monitor, incrementing its entry count.
• If another thread already owns the monitor associated with objectref, the thread blocks until the monitor’s entry count is zero, then tries again to gain ownership.

monitorexit: 
The thread that executes monitorexit must be the owner of the monitor associated with the instance referenced by objectref.
The thread decrements the entry count of the monitor associated with objectref. If as a result the value of the entry count is zero, the thread exits the monitor and is no longer its owner. Other threads that are blocking to enter the monitor are allowed to attempt to do so.

翻译如下:

  • monitorenter

每一个对象都会和一个监视器monitor关联.

监视器被占用时会被锁住,其他线程无法来获取该monitor.

当JVM执行某个线程的某个方法内部的monitorenter时,It will try to get the current object corresponding
的monitor的所有权.其过程如下:

  1. 若monior的进入数为0,线程可以进入monitor,并将monitor的进入数置为1.当前线程成为
    monitor的owner(所有者)

  2. 若线程已拥有monitor的所有权,允许它重入monitor,则进入monitor的进入数加1

  3. 若其他线程已经占有monitor的所有权,那么当前尝试获取monitor的所有权的线程会被阻塞,直
    到monitor的进入数变为0,才能重新尝试获取monitor的所有权.

  • monitorexit
  1. 能执行monitorexit指令的线程一定是拥有当前对象的monitor的所有权的线程.

  2. 执行monitorexit时会将monitor的进入数减1.当monitor的进入数减为0时,当前线程退出
    monitor,不再拥有monitor的所有权,此时其他被这个monitor阻塞的线程可以尝试去获取这个
    monitor的所有权
    monitorexit释放锁.
    monitorexit插入在方法结束处和异常处,JVM保证每个monitorenter必须有对应的monitorexit.

tips(重要)

简单的理解,monitor就是jvm底层的c++代码中的一个对象ObjectMonitor.

There is a counter in this object,To record whether the current object lock is used by anyone,用了多少次.

and some queues,Store and schedule some threads that need this lock.

关于monitor在c++里的结构,We will go into more detail below.

总结:

1、synchronized是靠ObjectMonitorto control the lock

2、The thread that needs this lock is theremonitorThe queue is arranged in various ways

3、The thread that got the lock ismonitor标记,Count up,释放锁,需要将计数器减减操作

1.3 Monitor详解

目标:Monitor的位置

file

Next we look at its detailed internal structure,and how it works.

1.3.1 Monitor是什么

目标: 通过JVM虚拟机源码分析synchronized监视器Monitor到底是什么

tips:

c++You can understand the source code,The principle must be understood

It's important during the interview,面试过去了就不重要!(瞎说什么大实话)

在HotSpot虚拟机中,monitor监视器是由ObjectMonitor实现的.

构造器代码src/share/vm/runtime/objectMonitor.hpp

hpp可以include包含cpp的东西,两者都是c++的代码

//构造器
ObjectMonitor() {
  _header = NULL;
  _count = 0; 
  _waiters = 0,
  _recursions = 0; // 线程的重入次数
  _object = NULL; 
  _owner = NULL; // 当前线程,The one who got the lock
  _WaitSet = NULL; // 等待队列,调waitThe thread is here
  _WaitSetLock = 0 ;
  _Responsible = NULL;
  _succ = NULL;
  _cxq = NULL; // 竞争队列,Can't earn a lock to advance here(Spinable)
  FreeNext = NULL;
  _EntryList = NULL; // 阻塞队列,来自cxq(调unlock时)或者waitSet(调notify时)
  _SpinFreq = 0;
  _SpinClock = 0;
  OwnerIsThread = 0;
}

Pay attention to these three lists:

1)cxq(Competitive list)

cxq是一个单向链表.A linked list of suspended threads waiting to re-compete for locks, monitor 通过CASwill be packaged intoObjectWaiterWrite to the head of the list.To avoid contention for inserting and removing elements,所以Ownerwill fetch elements from the end of the list.So this thing can be understood as the one who didn't get the lock when the competition came up and stayed here for a while(1级缓存).

2)EntryList(List of lock candidates)

EntryList是一个双向链表.当EntryList为空,cxq不为空,Owener会在unlock时,将cxq中的数据移动到EntryList.并指定EntryListThe first thread at the head of the list isOnDeck线程,The other threads just stay inside.So this thing can be considered as the secondary competition lock has not been obtained(One of them will be picked up soon).(2级缓存)

备注:EntryList跟cxq的区别

在cxqThe queue in can continue to spin waiting for the lock,Called if the spin threshold is reached and the lock is not acquiredpark方法挂起.而EntryListThe threads in are all suspended threads.

3)WaitList

WatiList是OwnerThread callwait()The thread entered after the method.进入WaitList中的线程在notify()/notifyAll()It will be added after the callEntryList.

过程总结:

  • Threads waiting for the lock will stay_cxq和entry set队列中,The specific one is related to the situation of the current thread taking the lock
  • entry setThe header thread gets the objectmonitor后进入_Owner区域并把monitor中的_ownerThe variable is set to itself,同时monitor中的计数器_count加1
  • 若线程调用wait()方法,将释放当前持有的monitor,_owner变量恢复为null,_count自减1,同时该线程进入_WaitSet集合中等待被唤醒.
  • 若当前线程执行完毕也将释放monitor(锁)并复位变量的值,以便其他线程进入获取monitor(锁).

1.3.2 详细流程图(了解)

monitorenter

monitorentercommand execution location:

JVM源码:src/share/vm/interpreter/interpreterRuntime.cpp

JVM函数入口:InterpreterRuntime::monitorenter

最终调用:src/share/vm/runtime/objectMonitor.cpp中的 ObjectMonitor::enter

file

monitorexit

执行monitorexit指令位置:

代码文件:src/share/vm/runtime/objectMonitor.cpp

调用函数:ObjectMonitor::exit

file

专注Java技术干货分享,欢迎志同道合的小伙伴,一起交流学习

原网站

版权声明
本文为[Learned Valley Wild Architects]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/221/202208091951428475.html