Java中的多个对象锁?

锁定私有字段变量(而不是使用锁定对象)是安全/可接受的做法吗? 这样,我可以有不同的锁用于不同的目的。 示例如下:

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; ... } 

注意始终使用最终成员var来锁定! 例如,如果您使用Integer ,并且计划更改它,那将是非常糟糕的做法,因为每次调用都会看到不同的对象并导致数据竞争。

无论您使用一个还是多个锁取决于您想要实现的协调方案,因此它完全是特定于域的。 您必须仔细考虑哪些操作是哪些操作,哪些操作不相互排斥,并适当地为它们分配锁定。 这里没有单一的最佳实践。

如果您的对象上有两个可能同时发生的正交操作而不会导致任何datarace,那么就是两个锁的情况。 在您的示例中,有两个整数,每个都独立更改。 我认为这是两个锁的情况。 如果你有更复杂的代码,在至少一个操作中你需要访问两个整数,那么将它们绑在一起,然后你需要一个锁。

锁定私有字段是完全可以接受的,只要该字段是对象即可。 基元没有内部锁,因此第一个片段无效。

但是,如果可以从外部访问此字段(例如,使用getter),我将避免锁定私有字段,因为这将允许任何人为同一目的锁定同一对象。 因此第二种解决方案是最干净的,恕我直言。

使用单个锁会适得其反,因为它会阻止对应该能够并发运行的方法的并发访问。 因此,通常更好的是具有细粒度的锁。

编辑:

既然你已经改变了你的问题并使用了包装器对象,那么对私有Integer实例的锁定实际上并不是一个好的解决方案,因为你在方法中更改了这些变量的值。 使用final字段作为锁

请记住,如果x是Integer实例,则x++等效于:

 int temp = x.intValue(); temp++; x = Integer.valueOf(temp); 

此外,由于Integer.valueOf()缓存了Integer实例,因此您可能有多个类使用相同的Integer实例来锁定完全不同的东西。 缓慢执行和死锁的方法。

我认为你应该对这两个领域有两个不同的锁。 锁定对象以防止两个或多个线程同时访问同一对象。

您还可以在java http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/Lock.html中查看Lock对象。它比同步更高效。 ,并且在java.util.concurrent中有一些实用程序类可以使用锁(如果需要,也可以使用ReadWriteLock)

AFAIK您使用的锁定对象仅作为ID。 我的意思是,你可以使用你想要的任何物体。 唯一重要的是“如果两件事必须互相排斥,那么他们必须使用相同的锁”。

所以使用自己的var的方法似乎没问题。

但要记住!!

  • 我不认为你可以锁定一个原语,它必须是一个Object
  • 如果更改字段值,则下一个进程将获得不同的锁定!

所以单独的锁似乎更安全。 除非你绝对确定你的领域不会改变(事实上,你应该宣布它是final )。