Java synchronized 两把锁的执行顺序

1. 整件事情的流程

在理解Java synchronized 两把锁为何会按顺序执行前,首先需要了解以下几个概念:

  • Synchronized关键字:用于修饰方法或代码块,保证同一时刻只有一个线程可以访问被修饰的方法或代码块。
  • 对象锁:Java中的每个对象都有一个内置的锁,也称为监视器锁。当一个线程访问一个方法或代码块时,会先获取该对象的锁,其他线程在获取锁之前会被阻塞。
  • 临界区:指的是一段代码,同一时刻只允许一个线程进入执行。

考虑以下代码片段:

public class MyClass {
    private Object lock1 = new Object();
    private Object lock2 = new Object();

    public void method1() {
        synchronized (lock1) {
            // 第一段同步代码块
        }
    }

    public void method2() {
        synchronized (lock2) {
            // 第二段同步代码块
        }
    }
}

在以上示例中,有两个方法method1method2,分别对应两段不同的同步代码块。这两段代码块使用了不同的对象锁lock1lock2

当一个线程执行method1方法时,它会获取lock1对象的锁,进入第一段同步代码块执行。同样地,当一个线程执行method2方法时,它会获取lock2对象的锁,进入第二段同步代码块执行。

2. 每一步需要做什么

下面我们逐步解释每一步需要做什么,以及对应的代码。

第一步:创建自定义类MyClass

public class MyClass {
    private Object lock1 = new Object();
    private Object lock2 = new Object();

    // ...
}

在这一步中,我们创建了一个自定义类MyClass,并定义了两个对象锁lock1lock2

第二步:定义method1方法

public void method1() {
    synchronized (lock1) {
        // 第一段同步代码块
    }
}

在这一步中,我们定义了method1方法,使用synchronized关键字修饰,参数为lock1。这意味着在调用method1方法时,只有获得lock1对象锁的线程才能进入第一段同步代码块执行。

第三步:定义method2方法

public void method2() {
    synchronized (lock2) {
        // 第二段同步代码块
    }
}

在这一步中,我们定义了method2方法,使用synchronized关键字修饰,参数为lock2。这意味着在调用method2方法时,只有获得lock2对象锁的线程才能进入第二段同步代码块执行。

第四步:创建多个线程并调用方法

public static void main(String[] args) {
    MyClass myObject = new MyClass();
    
    Thread thread1 = new Thread(new Runnable() {
        public void run() {
            myObject.method1();
        }
    });
    
    Thread thread2 = new Thread(new Runnable() {
        public void run() {
            myObject.method2();
        }
    });
    
    thread1.start();
    thread2.start();
}

在这一步中,我们创建了一个MyClass对象myObject。然后创建了两个线程thread1thread2,分别调用myObjectmethod1method2方法。

3. 代码注释

下面是以上代码中需要使用的每一条代码,并附带注释说明:

public class MyClass {
    private Object lock1 = new Object();  // 创建对象锁lock1
    private Object lock2 = new Object();  // 创建对象锁lock2

    public void method1() {
        synchronized (lock1) {  // 使用lock1对象锁
            // 第一段同步代码块
        }
    }

    public void method2() {
        synchronized (lock2