Java字节数组多线程
如果我有多个线程访问getter和setter,那么这段代码是否会遇到任何竞争条件?我不介意getter在set操作期间获取旧数据,但前提是它不会导致异常或获取nullJava字节数组多线程,java,multithreading,concurrency,thread-safety,race-condition,Java,Multithreading,Concurrency,Thread Safety,Race Condition,如果我有多个线程访问getter和setter,那么这段代码是否会遇到任何竞争条件?我不介意getter在set操作期间获取旧数据,但前提是它不会导致异常或获取null ConcurrentHashMap<String, Object> hashMap = new ConcurrentHashMap<String, Object> (); void setByteArray(String string, byte[] byteArray) { hashM
ConcurrentHashMap<String, Object> hashMap =
new ConcurrentHashMap<String, Object> ();
void setByteArray(String string, byte[] byteArray) {
hashMap.put(string, byteArray.clone());
}
byte[] getByteArray(String string) {
return ((byte[]) hashMap.get(string)).clone();
}
ConcurrentHashMap hashMap=
新的ConcurrentHashMap();
void setByteArray(字符串,字节[]byteArray){
put(字符串,byteArray.clone());
}
字节[]getByteArray(字符串){
return((字节[])hashMap.get(字符串)).clone();
}
这几乎是线程安全的(如果有这样的事情)。唯一缺少的是声明hashMap
字段final
。这保证了地图的真实性
除此之外,我没有发现任何问题(关于线程安全)。是线程安全的,因此存储和检索字节数组也应该是安全的
此外,由于您总是复制字节数组,因此除了存储在映射中的线程外,它们永远不会在线程之间共享。ConcurrentHashMap将安全地将它们发布到所有线程,因为它们从不被修改(这意味着它们实际上是不可变的),所以线程安全是有保证的
最后,根据评论,以下是关于其他一些方面的改进版本:
private final ConcurrentHashMap<String, Object> hashMap =
new ConcurrentHashMap<String, Object> ();
void setByteArray(String string, byte[] byteArray) {
hashMap.put(string, byteArray.clone());
}
byte[] getByteArray(String string) {
Object result = hashMap.get(string);
if(result == null)
return null;
else
return ((byte[]) result).clone();
}
private final ConcurrentHashMap hashMap=
新的ConcurrentHashMap();
void setByteArray(字符串,字节[]byteArray){
put(字符串,byteArray.clone());
}
字节[]getByteArray(字符串){
对象结果=hashMap.get(字符串);
如果(结果==null)
返回null;
其他的
返回((字节[])结果);
}
第一件事是hashMap
的private
修饰符,因此子类不能存储任何其他对象,例如共享字节数组
第二件事是getter中的null检查。您可能需要替换
返回null通过抛出新的IllegalArgumentException()代码>或其他一些,基于您的需求。ConcurrentHashMap
已设置好处理它,因此我的结论是您应该满足您的需求。看起来没问题,因为ConcurrentHashMap
处理线程安全,根据规范,您的代码不是线程安全的,不是因为字节,而是因为您使用ConcurrentHashMap的方式
要在映射中添加项目,应在put()上使用putIfAbsent()。
PutIfAbsent()相当于
if (!map.containsKey(key)){
return map.put(key, value);
}
else {
return map.get(key);
}
(可能使用正确的同步块或关键字)
若您只使用put(),则在多线程环境中可能会用新值覆盖现有值 是的,这段代码几乎是线程安全的,但别忘了声明hashmap private和final。因此,如果有人创建子类,他将无法破坏封装和线程安全性。如果经常克隆byte[]
,可能会非常昂贵。我假设你正在使用多个线程来改进性能,所以我会考虑一个避免克隆字节[S]的策略,建议检查哈希映射。之前为空cloning@BorisTreukhov,子类将无法断开线程安全性。实例化的对象是一个ConcurrentHashMap
@Nerrve,请看,问题中的代码似乎不是线程安全的。final不仅涉及替换引用,还涉及内存可见性。请看M.Topolnik回答:我很好奇,getByteArray(..)线程安全性如何?它正在执行“先检查后执行”的复合动作,这不是线程安全的。整个操作需要“锁定”,或者该方法可以简单地返回“hashMap.get()”,然后调用线程可以执行检查和克隆部分…@CaptainHastings“检查然后执行”只有在被检查的属性在执行操作之前发生更改时才是错误的。这在这里是不可能的,因为result
是一个局部变量,并且属性为null。