我有这个容器
private ConcurrentMap<Integer,SortedMap<Long,Object>> users;
在构造函数users = new ConcurrentHashMap<>();
并为每个用户获取new ConcurrentSkipListMap<>()
我有这个在threadpool中反复调用的方法
private void process(Object obj){
// SOME CODE
SortedMap<Long,Object> q = users.get( obj.userId);
logger.debug("SECTION 1");
q.headMap( someNumber ).clear();
logger.debug("SECTION 2");
q.put( obj.someId, obj );
logger.debug("SECTION 3");
}
使用executorService = Executors.newScheduledThreadPool(8);
executorService.execute(new Runnable() {
@Override
public void run() {
process(obj);
}
});
有时它工作正常,但有时(我认为在高负载下)某些用户进程方法(所有调用)都会卡住并且从不输出第2节
如果我交换q.headMap( someNumber ).clear();
和q.put( obj.someId, obj );
它仍然没有输出第2节
我也尝试了LinkedBlockingQueue
而不是ConcurrentSkipListMap
,但我有同样的问题
它看起来像死锁,但我没有在该结构上使用任何同步语句。
如果你有一个
,请分享你的想法答案 0 :(得分:2)
可能有多种原因;最明显的一个是非同步代码。采用线程转储来轻松识别原因。
一些问题:
在ConcurrentSkipListMap
JavaDocs中它在headMap()
处说:
The returned map will throw an IllegalArgumentException on an attempt to insert a key outside its range.
因此,如果obj.someId.compareTo(someNumber) < 0
您可以在IllegalArgumentException
获得put()
,而且不会在任何地方受到处理。
这也会导致竞争条件:
q.headMap( someNumber ).clear();
q.put( obj.someId, obj )
如果两个线程有(thread1) someNumber = (thread2) obj.someId
,你就会遇到竞争条件,并且知道底层会发生什么。此外,正如JavaDocs所说,clear()
不是原子操作。
你没有提到你使用users
引用对象的另一个地方;如何填充users
。
答案 1 :(得分:0)
它接缝问题不是代码卡住但它抛出异常,由theadpool静默处理。我试图推送自定义ThreadFactory与日志启用,但它仍然无法正常工作。解决方案是为RuntimeException提供正确的try catch
我所学到的教训是,如果你的部分代码没有在线程池中执行,那么可能是因为RuntimeException,你应该提供更多尝试来查找原因