首页 > 解决方案 > 如果两个线程使用不同的监视器,它们可以在同一个对象上执行相同的同步代码块吗?

问题描述

我对 Java 并发很陌生,我正在尝试更好地理解监视器。

假设我有一个对象,其方法采用某种引用参数并将该参数用作同步块中的监视器:

class Entity() {
    public void myMethod(Object monitor) {
        synchronized(monitor) {
            // critical stuff
        }
    }
}

如果两个线程使用不同的对象作为监视器,是否可以同时进入同一实体上的该部分?

final Entity myEntity = new Entity();
for (int i = 0; i < 3; i++) {
    new Thread() {
        public void run() {
            // Can these all run concurrently?
            myEntity.myMethod(new Object());
        }
    }.start();
}

如果我正确理解了监视器,那么是的,所有线程都可以同时进入同步块,因为每个监视器都充当完全不同的互斥锁,并且没有一个线程知道该块中的其他线程。

很难找到这方面的文档,因为教程似乎大多只是使用“this”作为监视器。

标签: javamultithreadingconcurrencyparallel-processingsynchronized

解决方案


如果两个线程对监视器使用不同的对象,是否可以同时进入同一实体上的该部分?

oracle 教程中可以阅读:

每个对象都有一个与之关联的内在锁。按照惯例,需要对对象字段进行排他和一致访问的线程必须在访问对象之前获取对象的内在锁,然后在完成访问时释放内在锁。在获得锁和释放锁之间,线程被称为拥有内在锁。只要一个线程拥有一个内在锁,其他线程就不能获得相同的锁。另一个线程在尝试获取锁时会阻塞。

这非正式地意味着可以使用任何 Java进行同步Object。由单个对象实例上的子句包围的块synchronized将按顺序执行,由持有正在同步对象的锁的线程执行。

如果两个线程对监视器使用不同的对象,是否可以同时进入同一实体上的该部分?

synchronized是的,只要每个线程都使用不同的对象实例进行同步,多个线程就可以(并行)执行用子句包裹的相同代码区域。

也可以使用class自身而不是其实例进行同步:

 synchronized (SomeClass.class){
     System.out.println("Hello World");
 } 

在这种情况下,所有使用synchronizedclass子句的线程SomeClass都必须相互同步

也可以synchronized在方法上使用子句(例如, public synchronized void method2());对于非静态方法,被同步的对象将是该方法所属的对象,而对于静态方法(例如, public static synchronized void method1())将是该方法所属的类本身。


推荐阅读