在此对象和其他对象上同步
Synchronizing on this and on other object
我想这个问题一定有人问过,但不幸的是,当我寻找它时,我只找到了不同的主题。无论如何,这是代码:
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 is locking whole object
一旦你正确理解了互斥锁(mutexes)的语义,你就会意识到这是一句空话。互斥量没有任何固有范围:线程在任何时间点都持有或不持有它。在 this
上同步只是获取与 this
实例关联的互斥量。在 lockZ
上同步获取一个完全独立的互斥量,并且可以同时获取两者。
foo2
和bar2
类似于foo1
和bar1
。在 bar2
的情况下,锁在 class A
对象上,而 foo2
正在使用对象 lockZ
.
的锁
对象 this
没有被锁定,而是对象 this
被用作互斥锁,主体被阻止与其他代码段同时执行 synchronized
this.
快速回答是:不。甚至 c2
也不受并发访问保护,因为它被不同的对象实例锁定。此外,更好的形式
public void bar2() {
synchronized(this) {
c2++;
}
}
是
synchronized public void bar2() {
c2++;
}
如@Marko 所述,锁定的语义与您已经设想的不同。
同步对象 X
并不意味着您正在对对象 X
本身应用 access/method 执行限制。当某个线程 A
在实例 X
上同步时,它会限制其他线程在同一实例 X
上同步,直到线程 A
在 synchronized(X)
中完成执行] 块,从而释放对对象 X
的锁定。更清楚地说,一次只有一个线程可以获取对象的单个不可变实例上的锁,并且在释放此锁之前,任何其他试图获取同一实例上的锁的线程都将阻塞。
将同步块想象成一个有门的房间,这扇门用钥匙打开,当一个线程想要进入房间并在里面做事时,它需要一把钥匙,打开门然后进去但是保留钥匙,其他想要使用相同钥匙进入房间的线程必须在门上等待,直到内部线程完成其业务,离开房间并释放钥匙以供其他线程使用。如果另一个线程使用不同的密钥,而另一个线程已经在房间里,它可以进入同一个房间并在里面做它的事情,而另一个线程还在里面,因此这两个线程可以修改房间里的相同东西,这可能会导致所谓的 race condition.
所以在你的情况下答案是:否。
我想这个问题一定有人问过,但不幸的是,当我寻找它时,我只找到了不同的主题。无论如何,这是代码:
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 is locking whole object
一旦你正确理解了互斥锁(mutexes)的语义,你就会意识到这是一句空话。互斥量没有任何固有范围:线程在任何时间点都持有或不持有它。在 this
上同步只是获取与 this
实例关联的互斥量。在 lockZ
上同步获取一个完全独立的互斥量,并且可以同时获取两者。
foo2
和bar2
类似于foo1
和bar1
。在 bar2
的情况下,锁在 class A
对象上,而 foo2
正在使用对象 lockZ
.
对象 this
没有被锁定,而是对象 this
被用作互斥锁,主体被阻止与其他代码段同时执行 synchronized
this.
快速回答是:不。甚至 c2
也不受并发访问保护,因为它被不同的对象实例锁定。此外,更好的形式
public void bar2() {
synchronized(this) {
c2++;
}
}
是
synchronized public void bar2() {
c2++;
}
如@Marko 所述,锁定的语义与您已经设想的不同。
同步对象 X
并不意味着您正在对对象 X
本身应用 access/method 执行限制。当某个线程 A
在实例 X
上同步时,它会限制其他线程在同一实例 X
上同步,直到线程 A
在 synchronized(X)
中完成执行] 块,从而释放对对象 X
的锁定。更清楚地说,一次只有一个线程可以获取对象的单个不可变实例上的锁,并且在释放此锁之前,任何其他试图获取同一实例上的锁的线程都将阻塞。
将同步块想象成一个有门的房间,这扇门用钥匙打开,当一个线程想要进入房间并在里面做事时,它需要一把钥匙,打开门然后进去但是保留钥匙,其他想要使用相同钥匙进入房间的线程必须在门上等待,直到内部线程完成其业务,离开房间并释放钥匙以供其他线程使用。如果另一个线程使用不同的密钥,而另一个线程已经在房间里,它可以进入同一个房间并在里面做它的事情,而另一个线程还在里面,因此这两个线程可以修改房间里的相同东西,这可能会导致所谓的 race condition.
所以在你的情况下答案是:否。