Java 装箱原语上的同步
我是多线程编程新手。所以我需要一些帮助来解决这个问题。我在一个装箱原语上发现了一个同步的findbugs错误: 我在这个网站上尝试了一些解决方案,但没有达到我的预期效果。有时我会从findbugs中得到类似的错误 我的代码需要对传递给构造函数的id进行锁定,下面是一些伪代码:Java 装箱原语上的同步,java,multithreading,findbugs,Java,Multithreading,Findbugs,我是多线程编程新手。所以我需要一些帮助来解决这个问题。我在一个装箱原语上发现了一个同步的findbugs错误: 我在这个网站上尝试了一些解决方案,但没有达到我的预期效果。有时我会从findbugs中得到类似的错误 我的代码需要对传递给构造函数的id进行锁定,下面是一些伪代码: public class MyClass{ public MyClass(long id){ synchronized(id){ // do some stuff }
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时,它竟然有如此严格的要求,这让我感到惊讶。通常,它只建议在性能方面做到最好。维护一个全局缓存并不总是比创建一个不会逃逸的临时对象好…