Java 在此对象和其他对象上同步

Java 在此对象和其他对象上同步,java,synchronization,Java,Synchronization,我想这个问题一定是在什么地方被问到的,但当我寻找它时,不幸的是,我发现只有不同的主题。无论如何,代码如下: public class A { Object lockX = new Object(); Object lockY = new Object(); Object lockZ = new Object(); int c1; int c2; public void foo1() { synchronized(lockX) {

我想这个问题一定是在什么地方被问到的,但当我寻找它时,不幸的是,我发现只有不同的主题。无论如何,代码如下:

public class A {
    Object lockX = new Object();
    Object lockY = new Object();
    Object lockZ = new Object();
    int c1;
    int c2;

    public void foo1() {
        synchronized(lockX) {
            c1++;
        }
    }

    public void bar1() {
        synchronized(lockY) {
            c1++;
        }
    }

    public void foo2() {
        synchronized(lockZ) {
            c2++;
        }
    }

    public void bar2() {
        synchronized(this) {
            c2++;
        }
    }
}
基本上,foo1和bar1是不正确的。它们使用不同的锁来保护c1,所以实际上c1不会受到保护,而且这两个函数可以同时运行。然而,我的问题是关于foo2和bar2。他们还好吗?它们也使用不同的锁,但bar2锁定了整个对象,所以它会阻止同时修改c2吗

bar2正在锁定整个对象


一旦正确理解互斥锁(互斥锁)的语义,您就会意识到这是一条空语句。互斥锁没有任何固有的作用域:线程在任何时间点都持有或不持有互斥锁。在
上同步只需获取与
实例关联的互斥锁。在
lockZ
上同步会获得一个完全独立的互斥锁,并且可以同时获得这两个互斥锁。

foo2
bar2
类似于
foo1
bar1
。在
bar2
的情况下,锁位于class
A
对象上,其中as
foo2
使用对象的锁
lockZ


对象
未被锁定,相反,对象
this
被用作互斥锁,并且主体被阻止与其他代码段同时执行
synchronized

快速回答是:不。即使是
c2
也不受并发访问的保护,因为它被不同的对象实例锁定。此外,一个更好的形式

    public void bar2() {
        synchronized(this) {
            c2++;
        }
    }


正如@Marko的文章中提到的,锁定的语义与您已经想到的不同

在对象
X
上同步并不意味着对对象
X
本身应用访问/方法执行限制。当某个线程
a
在一个实例
X
上同步时,它会限制其他线程在同一实例
X
上同步,直到线程
a
synchronized(X)
块内完成执行,从而释放对象
X
上的锁。更清楚地说,一次只有一个线程可以获取对象的单个不可变实例上的锁,并且在释放该锁之前,试图获取同一实例上的锁的任何其他线程都将阻塞

把一个同步块想象成一个有门的房间,这扇门是用钥匙打开的,当一个线程想要进入房间并在里面做事情时,它拿了一把钥匙,打开门,然后进入房间,但把钥匙放在里面,其他想要使用同一把钥匙进入房间的线程必须在门上等待,直到里面的线程完成其业务,离开房间并将钥匙释放给其他线程使用。如果另一个线程使用不同的密钥,而另一个线程已经在房间中,那么它可以进入同一个房间,在另一个线程仍在房间中的情况下在房间中执行其业务,因此这两个线程可以修改房间中的相同内容,这可能会导致所谓的错误


因此,在您的情况下,答案是:不。

您有四种不同的锁,
lockX
lockY
lockZ
this
。在一个实际的程序中,如果你只是想从多个线程中计算一些东西,你应该使用AtomicInteger。
    synchronized public void bar2() {
        c2++;
    }