盒装基元上的同步

时间:2014-05-13 18:21:51

标签: java multithreading findbugs

我是多线程编程的新手。所以我需要一些帮助来解决这个问题。我在一个盒装基元上得到了一个同步bug的异步错误:

http://findbugs.sourceforge.net/bugDescriptions.html#DL_SYNCHRONIZATION_ON_BOXED_PRIMITIVE

我在这个网站上尝试了一些解决方案,但它并没有像我预期的那样工作。有时我从findbugs得到类似的错误。

我的代码需要锁定一个id,我将其传递给构造函数,这里有一些伪代码:

public class MyClass{
   public MyClass(long id){
      synchronized(id){
         // do some stuff
      }    
   }
}

问题是,只有具有相同id的线程才应该阻塞同步块。具有不同ID的线程应该同时工作。

我也尝试过类似的东西,但它对我不起作用:

public class MyClass{

   private static final ConcurrentHashMap<Long, Object> myHashMap = new ConcurrentHashMap<Long, Object>();

   public MyClass(long id){

      Object object = getObject(id);

      synchronized(object){
         // do some stuff
      }    
   }

   private Object getObject(long id){
      if(!myHashMap.contains(id)){
         writeObject(id);
      }
      return myHashMap.get(id);
   }

   private synchronized void writeObject(long id){
      if(!myHashMap.contains(id)){
          myHashMap.put(id, new Object());
      }
   }
}   

在第二个例子中,我看到,我试图在hashmap中为每个id放置一个对象,但是 我意识到单元测试,具有相同id的线程进入synchronized块。但他们不应该这样做。如果有人有其他解决方案或如何处理这些问题,我将非常感激。

1 个答案:

答案 0 :(得分:4)

你写的单元测试对你有好处!供将来参考:你想要测试各种边缘值,这意味着对于数字至少为0,-1,1,MAX_VALUE,MIN_VALUE - 这会抓住你错过的第二个错误: - )

您的代码存在的问题是:synchronized(l) {}转换为:synchronized(Long.valueOf(l)){}valueOf缓存-128,127范围内的Longs,但即使这是可选(JLS只需要令人惊讶的整数!)。因此,只要您的ID大于127,您的整个计划就会崩溃。

你的第二种方法是可行的方法,但你不能只是让方法同步 - 只会在this上同步,所以不能保证静态地图的原子性。

而是做这样的事情:

Object newLock = new Object();
Object oldLock = map.putIfAbsent(id, newLock);
Object lock = oldLock != null ? oldLock : newLock;
synchronized(lock) { 

}