我有一个在服务器启动时初始化的静态HashMap
。客户登录时,客户端会从此地图初始化数据
现在我需要刷新此地图,但客户端可以同时登录并从此地图获取数据。
我可以在阅读时更改下面的地图参考吗?
我不能使用synchronized
,因为他们可以同时读入并且只有一个线程在写。
public void refresh() {
Map<String, Object> newMap = prepareData();
map = newMap;
}
答案 0 :(得分:1)
首先,您的地图需要声明为public void refresh() {
synchronized (MyClass.class) {
Map<String, Object> newMap = prepareData();
map = Collections.unmodifiableMap(newMap);
}
}
,以确保每个帖子都有最后一个版本,然后是您可以继续的方式:
private static volatile Map<String, Object> map = ...
您的地图将声明如下:
var list = $("#filedrop ul");
var dt = event.dataTransfer || (event.originalEvent && event.originalEvent.dataTransfer);
var files = event.target.files || (dt && dt.files);
for (var i = 0; i < files.length; i++) {
var file = files[i];
var reader = new FileReader();
reader.onload = function (e) {
var text = e.target.result;
var li = new $("<li class=\"list-group-item\">" + e.name + "</li>");
var del = new $("<span><i class=\"glyphicon glyphicon-trash\"></i></span>");
li.append(del);
li.attr("data-text", btoa(text));
list.append(li);
}
reader.readAsText(file);
}
答案 1 :(得分:1)
让我们假设“刷新”意味着您希望用从(例如)文件加载的新集替换散列映射中的所有条目。
如果新映射中的键集是原始映射中键的超集,则AND如果应用程序不关心客户端是否可以同时设置旧映射的一部分和新映射的一部分,然后您可以使用ConcurrentHashMap
代替HashMap
,并使用put
次调用替换这些条目。
但是,如果密钥是(或可能)不同,或者从客户端的角度来看更新需要是原子的,那么ConcurrentHashMap
将不起作用。相反,您需要将map
声明为volatile
并根据您的问题实施refresh()
方法。
正如您所指出的那样,使用synchronized
(或单一作者 - 多读取器锁定)可能会导致并发瓶颈。
注意:使用volatile
可能会比使用ConcurrentHashMap
提供更好的性能,即使后者是可行的解决方案。
答案 2 :(得分:1)
如果客户端有过时的数据,那么您需要做的就是创建一个新的地图并将静态参考指向它。如果新客户端在您执行此操作时出现,那么他们会获得过时的数据并且不会造成任何损害,如果他们在切换(重新分配)到新值之后出现,那么他们将获得新值。完成工作。
如果不行,那么您可能还必须通知其他客户在更新之前存在的有关更改的信息。在这种情况下,您希望使用观察者模式进行更新。在此模式中,如果客户端在更新期间连接,则可以正常运行,因为在更新完成后,它们将尽快更新。
顺便说一下:在所有情况下,你真的不应该使用静态&#39;为了任何东西。它只会导致问题。相反,创建一个非静态单例,用于保存地图并将其注入到客户端/服务/中。