Java 装箱原语上的同步

Java 装箱原语上的同步,java,multithreading,findbugs,Java,Multithreading,Findbugs,我是多线程编程新手。所以我需要一些帮助来解决这个问题。我在一个装箱原语上发现了一个同步的findbugs错误: 我在这个网站上尝试了一些解决方案,但没有达到我的预期效果。有时我会从findbugs中得到类似的错误 我的代码需要对传递给构造函数的id进行锁定,下面是一些伪代码: public class MyClass{ public MyClass(long id){ synchronized(id){ // do some stuff }

我是多线程编程新手。所以我需要一些帮助来解决这个问题。我在一个装箱原语上发现了一个同步的findbugs错误:

我在这个网站上尝试了一些解决方案,但没有达到我的预期效果。有时我会从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());
      }
   }
}   
公共类MyClass{
私有静态最终ConcurrentHashMap myHashMap=新ConcurrentHashMap();
公共MyClass(长id){
Object=getObject(id);
已同步(对象){
//做点什么
}    
}
私有对象getObject(长id){
如果(!myHashMap.contains(id)){
写对象(id);
}
返回myHashMap.get(id);
}
私有同步的void writeObject(长id){
如果(!myHashMap.contains(id)){
put(id,new Object());
}
}
}   
在您看到的第二个示例中,我尝试在hashmap中按id放置一个对象,但是
我实现了一个单元测试,具有相同id的线程进入同步块。但他们不应该这样做。如果有人有其他解决方案或如何处理这些问题,我将非常感激。

您编写了一个单元测试,这对您很好!供将来参考:您希望测试所有类型的边值,这意味着对于至少0、-1、1、MAX\u值、MIN\u值的数字-这将捕获您错过的第二个错误:-)

代码的问题是:
synchronized(l){}
转换为:
synchronized(Long.valueOf(l)){}
valueOf
缓存-128、127范围内的long,但即使这样也是可选的(JLS仅对整数要求它!)。因此,一旦您的ID大于127,您的整个方案就会崩溃

您的第二个方法是要走的路,但是您不能仅仅使该方法同步-这将只在
this
上同步,因此不能保证静态映射的原子性

相反,你可以这样做:

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

}

你想达到什么目标?这是某种缓存吗?你能展示你的单元测试吗?(您的第二种方法看起来不错,只是get方法不是原子的,put方法是同步的,这没有意义)。我尝试锁定每个id的对象,这意味着如果id=1的线程进入同步块,它应该排除id=1的所有其他线程。但是具有不同ID的线程可以并行工作。问题是,正如我提到的,JVM中的原语类型和装箱原语使用(某种程度上)相同的实例,这很危险。这意味着锁定primitive或boxed primitve会导致具有相同id=1的线程可以进入临界区。您如何知道具有相同id的不同线程同时处于临界区?您确定这不是测试代码中的错误吗?在我的JVM中,我的测试用于原语值。所以我用原语和对象进行了测试。第一个解决方案对我有效,我的测试没有失败。但第二个解决方案失败了。我做了一些输出,看看我创建的HashMap是否正确。每个id都有一个实例看起来很好。我会尽快发布代码或其中的一部分。我的文件看起来是这样的:这是一个比我的好得多的解决方案。呃,如果没有键的映射,putIfAbsent()将返回null。@JB哦,对了,记住API就好了。这实际上更有意义。谢谢,非常感谢。你救了我一天:)我认为这是一条路。“JLS只对整数有惊人的要求”-事实上,当我第一次阅读JLS for Java 5时,它竟然有如此严格的要求,这让我感到惊讶。通常,它只建议在性能方面做到最好。维护一个全局缓存并不总是比创建一个不会逃逸的临时对象好…