我有这个类有3个读取方法和1个写入方法:
class ResourceClass {
private static Map resourceMap = new HashMap();
// New method to update resource
public void write(String key, Object resource) {
resourceMap.put(key, resource);
}
public Object read(String var1) {
return resourceMap.get(var1);
}
public Object read(String var1, String var2) {
// .. Do task with var1 and var2
return resourceMap.get(var1);
}
public Object read(String var1, String var2, String var3) {
// .. Do task with var1, var2 and var3
return resourceMap.get(var1);
}
}
目前,此类仅包含一个写入和3个读取方法来使用静态资源。此配置的问题在于,更新resourceMap
的唯一方法是重新启动应用程序,以便再次创建ResourceClass
,resourceMap
将添加到类中供其使用。
我想要的是添加一些动态方式来更新resourceMap
而不重新启动服务,但为此我必须使此类线程安全,以便处理write
方法来更新resourceMap
安全。为此,我可以选择在synchronized
和read
方法中使用write
关键字,因此只有一个线程可以访问resourceMap
。 此方法可以解决问题,但也包括其他问题。这些read
方法是高并发方法,因此添加synchronized
关键字会严重影响服务性能,当然我们也不希望这样做。
是否有任何机构知道一种方法来保持线程读取(不会相互阻塞)但是当有一个线程到write
所有read
方法时等待写完成并在{ {1}}完成?
答案 0 :(得分:3)
正如@Mike Mnomonic在评论中所说,ConcurrentHashMap是一个具有可调整并发级别的线程安全映射。与其他哈希映射一样,ConcurrentHashMap
具有后备数组;根据您指定的并发级别(默认值为16),每个子阵列只有一个锁定,这个后备阵列被拆分为多个子阵列,例如,如果您的容量为128,并且使用的默认并发级别为16,那么子阵列[0,8]有自己的锁,[8,16]有自己的锁,[16,24]有自己的锁,依此类推,所以两个线程可以写入两个不同的子阵列而不会相互阻塞。
如果写入次数非常少,那么ImmutableMap包含的AtomicReference可能会提高效果。
private final AtomicReference<ImmutableMap<String, Object>> resourceMap;
public void write(String key, Object value) {
boolean success = false;
while(!success) {
ImmutableMap oldMap = resourceMap;
ImmutableMap.Builder<String, Object> builder = ImmutableMap.builder();
builder.putAll(resourceMap.entrySet());
builder.put(key, value);
success = resourceMap.compareAndSet(oldMap, builder.build());
}
}
public Object read(String var1) {
...
return resourceMap.get().get(var1); // get map, then get value
}
public Object read(String var1, String var2);
public Object read(String var1, String var2, String var3);
在write
上复制旧地图,添加新值,并为旧地图交换新地图;如果两个更新试图互相攻击,那么只有一个会成功,同时另一个将继续重试,直到其更新为止。读者不需要关心任何这些 - 他们只是get
当前的地图。
答案 1 :(得分:1)
对于高读取重负载,请考虑克隆集合并添加到克隆中,然后将结果分配给字段。
如果可以同时调用write方法,则可能需要进行工作以确保对此方法的访问是“线程安全的”。