Java中的多对象锁?
锁定私有字段变量(而不是使用锁定对象)是否安全/可接受?这样,我就可以为不同的目的使用不同的锁。示例如下:Java中的多对象锁?,java,multithreading,concurrency,locking,synchronized,Java,Multithreading,Concurrency,Locking,Synchronized,锁定私有字段变量(而不是使用锁定对象)是否安全/可接受?这样,我就可以为不同的目的使用不同的锁。示例如下: class Test { private Integer x = 0; private Integer y = 0; public void incrementX() { synchronized(x) { x++; } } public void decrementX() { synchronized(x) { x+
class Test {
private Integer x = 0;
private Integer y = 0;
public void incrementX() {
synchronized(x) {
x++;
}
}
public void decrementX() {
synchronized(x) {
x++;
}
}
public void incrementY() {
synchronized(y) {
y++;
}
}
public void decrementY() {
synchronized(y) {
y++;
}
}
或者我应该为我希望锁定的每个私有成员设置一个锁定对象吗?例如:
class Test {
private final Object xLock = new Object();
private final Object yLock = new Object();
private Integer x = 0;
private Integer y = 0;
...
}
class Test {
private final Object objLock = new Object();
private Integer x = 0;
private Integer y = 0;
...
}
或者我应该只使用一个通用锁,并将其用于所有需要锁定的私有变量?例如:
class Test {
private final Object xLock = new Object();
private final Object yLock = new Object();
private Integer x = 0;
private Integer y = 0;
...
}
class Test {
private final Object objLock = new Object();
private Integer x = 0;
private Integer y = 0;
...
}
注意始终使用最后一个成员var进行锁定!例如,如果您使用一个
整数
,并计划对其进行更改,这将是非常糟糕的做法,因为每次调用都会看到不同的对象并导致数据竞争
是否使用一个或多个锁取决于您想要实现的协调方案,因此它完全是特定于域的。您必须仔细考虑哪些操作是互斥的,哪些操作不是互斥的,并适当地为它们分配锁。这里没有单一的最佳实践
如果在对象上有两个可能同时发生的正交操作,而不会导致任何数据竞争,那么就需要两个锁。在您的示例中,有两个整数,每个整数独立变化。我认为这是一个双锁的例子。如果您有更复杂的代码,其中至少有一个操作需要访问两个整数,这将把它们绑定在一起,然后您将需要一个锁。锁定私有字段是完全可以接受的,只要该字段是一个对象。原语没有内部锁,因此第一个代码段无效 但是,如果可以从外部访问私有字段(例如,使用getter),我将避免锁定该字段,因为这将允许任何人出于不同目的锁定同一对象。因此,第二种解决方案是最干净的,IMHO 使用单个锁会适得其反,因为它会阻止对应该能够并发运行的方法的并发访问。因此,通常最好使用细粒度的锁 编辑: 既然您已经更改了问题并使用了包装器对象,那么锁定私有整数实例并不是一个好的解决方案,因为您在方法中更改了这些变量的值将最终字段用作锁 请记住,如果
x
是整数实例,则x++
相当于:
int temp = x.intValue();
temp++;
x = Integer.valueOf(temp);
此外,由于Integer.valueOf()缓存整数实例,因此可能有多个类使用同一个整数实例来锁定完全不同的对象。执行缓慢和死锁的秘诀。我认为这两个字段应该有两个不同的锁。锁定对象以防止两个或多个线程同时访问同一对象 您还可以查看java中的Lock对象
它的性能比synchronize更高,在java.util.concurrent中有一些实用程序类可以使用锁(如果需要,还可以使用ReadWriteLock)AFAIK您使用的锁对象仅作为ID。我的意思是,您可以使用任何您想要的对象。唯一重要的是“如果两个东西必须相互排斥,那么它们必须使用相同的锁” 因此,使用自己的var的方法似乎是可行的 但是,记住
- 我认为不能锁定原语,它必须是
对象
- 如果更改字段值,下一个进程将获得不同的锁李>
因此,单独的锁似乎更安全。除非你绝对确定你的字段不会改变(事实上,你应该声明它为<代码>最终< /代码>)。< /P>为原语,考虑使用原子*变体,例如AtomicIntegerNote,你实际上不“锁定在一个私人领域”。您总是锁定对象(这就是原语不起作用的原因)。通常区别并不重要,但如果字段引用的对象发生变化,那么它就会变得非常重要。我们不能在基本体上同步?@maress:不,你不能。监视器是对象的属性,原语不是对象,因此它们没有监视器。将其设置为最终值非常重要。由于这个原因,问题中的第一个实现将无法工作-如果一个线程正在对原始对象进行变异,那么不同的线程将看到不同的
Integer
对象。因此,互斥将不会像预期的那样起作用。第二个实现在这方面更好。@Marko当然。在我的代码中,我实际上使用了很多私有对象进行同步。