使用Map计算解决Java线程可见性和并发错误



我使用Java 8。我有一个事件处理程序,它以很高的速率(每秒n个(接受事件,当我得到这么多事件(在这个简化的例子中是1000(时,我想将它们刷新到存储中

我在25号myCache.get(event.getKey()).add(event.getBean());线上有能见度错误吗?我应该在handleEvent()方法上同步吗?

public class myClass extends MySimpleEventHanlder {
private Map<String, List<MyBean>> myCache;
private ScheduledExecutorService scheduler;
public void MyClass() {
myCache = new ConcurrentHashMap<String, List<MyBean>>();
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(() -> {
for (Iterator<Map.Entry<String, List<MyBean>>> it = myCache.entrySet().iterator(); it.hasNext();) {
Map.Entry<String, List<MyBean>> entry = it.next();
if (entry.getValue().size() >= 1000) {
it.remove();
//do some more processing , flush to storage
}
}
}, 0, 60, TimeUnit.SECONDS);
}
@Override
public void handleEvent(Event event) {
if (myCachetCache.containsKey(event.getKey())) {
myCache.get(event.getKey()).add(event.getBean());
}
else{
List<MyBean> beans = new ArrayList<MyBeans>();
beans.add(event.getBean());
myCache.put(event.key, beans);
}
}
}

您肯定存在可见性问题:您在一个线程中将项添加到ArrayList中,然后在另一个线程中从该ArrayList读取size((,其间没有同步。

另一个问题是密钥可能在对myCache.containsKeymyCache.get的调用之间被移除。这将导致NullPointerException。这可以通过使用保证是原子的计算来解决。

myCache.compute(event.getKey(), (key, value) -> {
if (value == null) {
value = new ArrayList<>();
}
value.add(event.getBean());
return value;
});

最新更新