有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

多线程Java ConcurrentSkipListMap在某些线程中卡住

我有这个容器

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,但我有同样的问题

它看起来像一个死锁,但我没有在该结构上使用任何同步语句

如果你有想法,请分享你的想法


共 (2) 个答案

  1. # 1 楼答案

    可能有多种原因;最明显的是不同步的代码。进行线程转储以轻松确定原因

    一些问题:

    ConcurrentSkipListMapJavaDocs中,它在headMap()中说:

    The returned map will throw an IllegalArgumentException on an attempt to insert a key outside its range.
    

    因此,如果obj.someId.compareTo(someNumber) < 0,你可以在put()得到一个IllegalArgumentException,它在任何地方都不会被治疗

    这也会导致比赛条件:

    q.headMap( someNumber ).clear();
    q.put( obj.someId, obj )
    

    如果两个线程都有(thread1) someNumber = (thread2) obj.someId,那么你就会得到一个竞争条件,谁知道下面会发生什么。此外,正如JavaDocs所说clear()不是原子操作

    你没有提到你使用users指代对象的另一个地方;如何填充users

  2. # 2 楼答案

    问题不在于代码被卡住,而是它抛出异常,异常由ADPool静默处理。我试图通过启用日志功能来推动定制ThreadFactory,但它仍然不起作用。解决方案是为运行时异常提供适当的尝试捕获

    所以我学到的教训是,如果部分代码没有在线程池中执行,可能是因为RuntimeException,您应该提供更多的try Catch来查找原因