如何在JVM内部发生java对象锁定和监视器创建

Ins*_*der 8 java concurrency multithreading jvm-hotspot

假设我有以下代码片段,其中两个线程访问具有两个关键部分(同步语句)的相同方法.这些同步语句中的每一个都被赋予不同的锁定对象.代码如下:

public class MyWorker {
private Random random = new Random();

private Object lock1 = new Object();
private Object lock2 = new Object();

private List<Integer> list1 = new ArrayList<>();
private List<Integer> list2 = new ArrayList<>();

private void stageOne() {

    synchronized (lock1) {
        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        list1.add(random.nextInt(100));
    }

}

private void stageTwo() {

    synchronized (lock2) {
        try {
            Thread.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        list2.add(random.nextInt(100));
    }

}

private void process() {
    for (int i=0; i<1000; i++) {
        stageOne();
        stageTwo();
    }

}

void main() {

    Thread t1 = new Thread(this::process);

    Thread t2 = new Thread(this::process);

    t1.start();
    t2.start();

    try {
        t1.join();
        t2.join();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

}

}
Run Code Online (Sandbox Code Playgroud)

我的问题不是关于这段代码中的错误或者它是如何在java站点中执行的.这段代码工作正常.我只是将其作为参考代码,以便回答的人有一个特定的场景来引用我想知道JVM如何在内部创建与此实例关联的监视器对象以及如何使用OpenJDK实现根据此场景在内部进行对象锁定.我期待一个低级别的解释.

我研究了这个主题几天,但是找不到深入的解释.这些是我经历的一些调查结果:

  • 这个stackoverflow问题 Java锁概念内部如何工作?.但我无法在答案中找到彻底的解释.
  • JLS 17.1提供了关于监视器如何在高级别中工作的语言解释,而不是"内部发生"的语言解释.

这些方法中最基本的是同步,它是使用监视器实现的.Java中的每个对象都与一个监视器相关联,一个线程可以锁定或解锁.一次只有一个线程可以锁定监视器.尝试锁定该监视器的任何其他线程都将被阻止,直到它们可以获得该监视器上的锁定为止.线程t可以多次锁定特定监视器; 每次解锁都会逆转一次锁定操作的效果.

在Java虚拟机中,每个对象和类在逻辑上与监视器关联.对于对象,关联的监视器保护对象的实例变量.对于类,监视器保护类的类变量.如果对象没有实例变量,或者类没有类变量,则关联的监视器不保护数据.

为了实现监视器的互斥功能,Java虚拟机将锁(有时称为互斥锁)与每个对象和类相关联.锁就像一个特权,任何时候只有一个线程可以"拥有".线程无需获取锁来访问实例或类变量.但是,如果一个线程确实获得了一个锁,那么在拥有该锁的线程释放它之前,没有其他线程可以获得对相同数据的锁定.("锁定对象"是获取与该对象关联的监视器.)

我在指令集级别知道如何使用monitorentermonitorexit操作码来管理同步语句.但我试图通过JVM源代码级别更深入地了解.但是我正在努力将OpenJDK源代码映射到我通过上面链接找到的高级解释,因为源代码中有很多内容.

那么熟悉OpenJDK源代码的人是否可以使用OpenJDK源代码解释以下与上述代码片段相关的问题?我认为ObjectMonitor,BasicLock,Synchronizer类与此解释更相关.

  1. 为哪个对象实例创建监视器对象?它是针对MyWorker对象实例Object lock1还是两者兼而有之?因为JSL和Bill Vennams的解释描述了每个对象都与监视器相关联.
  2. 如果它是MyWorker对象实例,那么如何为对象实例创建监视器MyWorker
  3. 如何为Object lock1 我们传递的引用对象创建锁定对象
  4. 实际监视器是如何被线程的锁定对象锁定的?

And*_*eas 5

为哪个对象实例创建监视器对象?

每个 Java对象也是一个监视器对象,包括反射对象,因此您的代码至少具有以下内容:

  • 类的对象 MyWorker
  • 类的对象 Random
  • 类的对象 Object
  • 类的对象 List
  • 类的对象 Integer
  • 类的对象 ArrayList
  • ... 还有很多 ...
  • Random 分配给字段的实例 random
  • Object 分配给字段的实例 lock1
  • Object 分配给字段的实例 lock2
  • ArrayList 分配给字段的实例 list1
  • ArrayList 分配给字段的实例 list2
  • Thread 实例分配给局部变量 t1
  • Thread 实例分配给局部变量 t2
  • Integer调用时由自动装箱创建的每个实例add(random.nextInt(100))

它适用于MyWorker对象实例还是Object lock1或两者兼而有之?

如果是MyWorker对象实例,那么如何为MyWorker对象实例创建监视器?
如何为引用对象创建锁定对象我们传递的对象lock1
如何实际监视器被线程的锁定对象锁定?

取决于JVM内部.对此没有单一的答案,"彻底的解释"超出了本网站的范围.

  • @Insightcoder,因为你一次问了十几个问题,你不应该责怪回答者解决了90%的问题而忽略了你的实际问题.如果您的实际问题是JVM如何在最低级别实现锁定,那么90%的问题文本都是过时的噪音. (4认同)
  • 是的,这是一个通用的低级问题,与Java没有任何关系.这就是为什么我在问题中提到"我的问题不是关于此代码中的错误或它是如何执行的".我只将Java代码作为参考,以便可以解释低级别的执行.我特地请求有OpenJDK源代码经验的人的帮助.但似乎所有"不"回答的赞成者甚至不理解这个问题都是关于特定java代码的低级别解释. (2认同)