如果 Java 中的监视对象不同,是否可以 2 个线程执行相同的同步实例方法?

Could 2 threads execute the same synchronized instance method if the monitor object is different in Java?

提问人:elvis 提问时间:8/21/2023 最后编辑:Mureinikelvis 更新时间:8/21/2023 访问量:73

问:

我是 Java 并发的新手,我知道同步的实例方法意味着一次只有一个线程可以执行该方法。但是这件事是否取决于监视对象?如果监视对象不同,是否可以同时执行相同的同步实例方法?

例如:这是一个例子,但我不确定它是否是一个好例子。我只是想知道是否可以同时调用同步方法或阻止两个或多个线程。或者始终无法调用同步方法

public class SynchronizedExchanger {

    protected Object object = null;

    public synchronized void setObject(Object o) {
        System.out.println("Do something, o = " + o);
        this.object = o;
    }
}

public class SynchronizedExchangerMainDemo {
    public static void main(String[] args) {
        SynchronizedExchanger exchanger = new SynchronizedExchanger();
        SynchronizedExchanger exchanger1 = new SynchronizedExchanger();

        Thread thread1 = new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        for (int i = 0; i < 1000; i++) {
                            exchanger.setObject("" + i);
                        }
                    }
                }
        );

        Thread thread2 = new Thread(
                new Runnable() {
                    @Override
                    public void run() {
                        for (int i = 0; i < 1000; i++) {
                            exchanger1.setObject("" + i);
                        }
                    }
                }
        );

    }
}
Java 多线程 并发 同步

评论

1赞 Arvind Kumar Avinash 8/21/2023
在您的问题中添加一些代码,以便人们可以准确地理解您的要求。另外,保持你的问题重点突出。希望这篇文章能回答您的问题。
0赞 user16320675 8/21/2023
Java 语言规范 8.4.3.6. 同步方法:“同步方法在执行之前获取监视器 (§17.1)。对于类(静态)方法,使用与该方法的类的 Class 对象关联的监视器。对于实例方法,使用与此关联的监视器(调用该方法的对象)。 - 这意味着:(i) 静态同步方法不能由 2 个线程执行;(ii) 同一实例上的非静态同步方法,不能由 2 个线程执行
2赞 user16320675 8/21/2023
--> "monitor object is different“: 是的,2 个线程可以在两个不同的实例上运行相同的实例方法(对于不同监视器上的任何方法或同步块始终为 true) ||(顺便说一句,编辑后(添加代码):代码什么也没做,因为线程没有启动 - 否则,两者将相互独立运行)

答:

1赞 Mureinik 8/21/2023 #1

如果实例方法声明为 ,这意味着它在 上隐式同步,因此根据定义,受监视的对象将是相同的,并且只有一个线程可以在给定时间执行该方法。synchronizedthis

如果该方法未声明为 ,而是使用显式块,则仅使用相同的监视对象将阻止并发执行。如果两个线程使用不同的监视器对象,则它们可以并发执行。synchronizedsynchronized

评论

0赞 user16320675 8/21/2023
此外,如果方法是 ,则没有 ,则同步在包含该方法的对象上(即使与问题无关,但也许读者需要知道这一点)staticthisClass
0赞 elvis 8/21/2023
@Mureinik谢谢!我只想知道如果监视对象不同,是否可以同时执行 2 个线程,例如在我拥有的示例中
0赞 Mureinik 8/21/2023
@elvis 在您添加的示例中,方法是 。 使用实例作为监视器,并以类似方式使用实例,因此两个线程不会相互阻塞。synchronizedexchanger.setObjectexchangerexchanger1.setObjectexchanger1
1赞 Solomon Slow 8/21/2023 #2

,并引用两个不同的实例。这两个线程绝对可以“同时”调用,因为 是同步的,并且引用一个线程中的实例,但它引用另一个线程中的实例。exchangerexchanger1setObjectsetObjectthisthisexchangerexchanger1

synchronized(o)仅防止多个线程同时在同一个对象 o 上同步。当你写的时候:

synchronized MyType mymethod(...) {
    doSomeStuff(...);
    return something;
}

这只是以下方面的捷径:

MyType mymethod(...) {
    synchronized(this) {
        doSomeStuff(...);
        return something;
    }
}

如果只有一个实例,并且两个线程都在它上运行,那就不同了。在这种情况下,将在两个线程中引用同一个对象,并且两个线程在任何时候都不允许同时位于该对象上。SynchronizedExchangerthissynchronized

1赞 Nathan Hughes 8/21/2023 #3

监视器是互斥锁,它是线程为了获得对同步代码的独占访问权限而获取的东西。例如,方法,监视器位于对象实例上,对于静态方法,监视器位于类对象上。

因此,如果两个线程没有获取相同的监视器,则也不会将另一个线程排除在外。