1

For instance,

class Test{
   static Map a = new ...
   static Map b = new ...

   public void process(){

      ...
      a.put(...);
      b.put(...);
  } 
} 

Do I have to lock like this:

 synchronized(a){
     a.put();
 }

 synchronized(b){
     b.put(b);
 }

This seems to be awkward. Any other right way to do this? Thanks.

4

3 回答 3

2

不,您需要在一个synchronized块中执行这两个操作,否则另一个线程可能会看到两个映射之间的不一致。

一种可能的选择是使用一种synchronized方法,或者您可以使用其他一些私有对象或其中一个地图作为监视器。这是同步方法示例:

    static Map a = new ...
   static Map b = new ...

   public synchronized void process(){

      ...
      a.put(...);
      b.put(...);
  } 
} 
于 2013-04-13T18:13:26.467 回答
1

您可以使用专用对象,例如

Object mapLock = new Object();

同步。

或者您可以同步a在记住,即使您需要访问b您也需要同步a

一般来说,同步this不是一个好主意。我的意思是这是一个坏习惯,如果不是在这个应用程序中而是在您制作的其他应用程序中,这样做最终可能会导致性能不佳或不明显的死锁。

在 Java 中避免同步(this)?

您还可以考虑使用并发包中的 ReadWriteLock。

于 2013-04-13T18:43:12.593 回答
0

您确实需要在一个synchronized块内运行这两个操作。值得注意的是,在您的示例中,您已经静态定义了映射,而该process()方法是实例方法。同步方法意味着对该实例的调用将被同步,但对 2 个不同实例的调用不会(因为将同步关键字应用于方法时使用的锁是有效的this)。您可以将 process() 方法设为静态,或者使用synchronized(Test.class) {}块代替以确保不会发生竞速。

您还需要注意如何将地图公开给客户 - 如果您将它们作为属性提供,那么我可能会用 Collections.unmodifiableMap() 将它们包装起来,以确保没有其他东西可以与他们一起搞砸您没有在寻找 - 但是这并不能完全防止客户遇到“奇怪”的时间,因为他们仍然会看到更改以潜在不安全的方式发生。因此,我也可能将类型声明为 ConcurrentHashMap 以使事情更安全一些(尽管仍然存在一些危险的操作,例如在线程之间共享迭代器)

于 2013-04-13T18:40:02.313 回答