Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/360.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java中的多对象锁?_Java_Multithreading_Concurrency_Locking_Synchronized - Fatal编程技术网

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当然。在我的代码中,我实际上使用了很多私有对象进行同步。