我是多线程编程的新手。所以我需要一些帮助来解决这个问题。我在一个盒装基元上得到了一个同步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块。但他们不应该这样做。如果有人有其他解决方案或如何处理这些问题,我将非常感激。
答案 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) {
}