java - Java 8中等待状态线程不断增加的原因是什么

标签 java multithreading java-8 concurrency

今天我发现我的 Java 8 应用程序有很多线程处于 WAITING 状态:

[arthas@1]$ thread --state RUNNABLE
Threads Total: 3427, NEW: 0, RUNNABLE: 17, BLOCKED: 0, WAITING: 3114, TIMED_WAITING: 296, TERMINATED: 0                                                                              
ID             NAME                                         GROUP                          PRIORITY       STATE          %CPU           TIME           INTERRUPTED    DAEMON         
124            pool-11-thread-25                            main                           5              RUNNABLE       75             0:0            false          false          
53             as-command-execute-daemon                    system                         10             RUNNABLE       23             0:0            false          true           
133            Thread-20                                    main                           5              RUNNABLE       1              0:2            false          true           
28             Apollo-RemoteConfigLongPollService-1         Apollo                         5              RUNNABLE       0              0:0            false          true           
32             Attach Listener                              system                         9              RUNNABLE       0              0:0            false          true           
99             DestroyJavaVM                                main                           5              RUNNABLE       0              0:39           false          false          
4              Signal Dispatcher                            system                         9              RUNNABLE       0              0:0            false          true           
19             grpc-default-worker-ELG-1-1                  main                           5              RUNNABLE       0              0:0            false          true           
21             grpc-default-worker-ELG-1-2                  main                           5              RUNNABLE       0              0:0            false          true           
97             http-nio-11003-Acceptor                      main                           5              RUNNABLE       0              0:0            false          true           
85             http-nio-11003-BlockPoller                   main                           5              RUNNABLE       0              0:0            false          true           
96             http-nio-11003-ClientPoller                  main                           5              RUNNABLE       0              0:0            false          true           
54             lettuce-nioEventLoop-4-1                     main                           5              RUNNABLE       0              0:0            false          true           
70             lettuce-nioEventLoop-4-2                     main                           5              RUNNABLE       0              0:0            false          true           
36             nioEventLoopGroup-3-1                        system                         10             RUNNABLE       0              0:0            false          false          
42             nioEventLoopGroup-3-2                        system                         10             RUNNABLE       0              0:0            false          false          
37             nioEventLoopGroup-4-1                        system                         10             RUNNABLE       0              0:0            false          false          
Affect(row-cnt:0) cost in 120 ms.

有 3000+ 线程处于 WAITING 状态,现在我随机选择一个 WAITING 线程池线程,显示如下::

[arthas@1]$ thread 4410
"pool-96-thread-10" Id=4410 WAITING on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@3e27c029
    at sun.misc.Unsafe.park(Native Method)
    -  waiting on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@3e27c029
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
    at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1088)
    at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
    at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1074)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1134)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)

Affect(row-cnt:0) cost in 16 ms.

但问题是我不知道线程从哪里启动以及是什么导致等待线程增加。有什么方法可以找出从哪里启动线程或者为什么 WAITING 线程增加?我现在使用Java ThreadExecutor。目前等待线程高达6000+。我添加自定义配置:

@Configuration
public class ScheduleConfig implements SchedulingConfigurer {

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setScheduler(Executors.newScheduledThreadPool(30));
    }

}

enter image description here

最佳答案

您显示的堆栈跟踪是“情况正常”:这是一个线程池执行器线程已准备好执行工作,但工作队列为空。在这种情况下,“等待”的意思是:我正在等待工作要做,而不是:“我有事情要做,但不能做,因为我正在等待事情先完成”。

现在,3000 个线程本身就有些令人担忧;每个线程都有自己的堆栈空间。该大小取决于您的 -Xss 参数,但它们往往从 64k 到 1MB。如果是 1MB,那就是... 3GB 堆栈空间,那是... 次优。在虚拟机升温后,这个数字(等待作业接受的线程数)也不应该增长太多。

如果所有/大多数等待线程都有类似的跟踪,那么实际上只有两个选择:

  • 您创建了一个执行程序,并随着时间的推移不断要求它添加越来越多的线程。我对此表示怀疑,但这是可能的。
  • 你一直在创造执行者。不要这样做。

执行器背后的想法是,您只制作一个,或者至少制作很少的一个。

如果您必须将它们创建为正在运行的应用程序的一部分(与创建作业并将其提供给单例执行器的正常情况相比),那么请注意它们实际上是资源:如果您不“关闭”它们,你的进程将需要越来越多的资源,直到最终虚拟机耗尽而崩溃。

要关闭它们,您可以调用 shutdown() ,它会很好地询问,而 shutdownNow() 则更积极,并且会执行任何尚未选择的作业永久撤消。

所以,回顾一下:

  • 您正在应用程序的正常处理过程中创建新的执行程序。在代码库中搜索 new ScheduledThreadPoolExecutor 并检查情况。如果您必须查看实际情况,请添加一些日志记录。
  • 那么,最有可能的是,您希望解决此问题并首先停止创建新的执行器 - 只需创建一个,一次,然后将作业提供给这个执行器即可。
  • 如果制作它们确实有意义,请使用一些监护结构来确保在使用完它们后也能清理它们。您可以搜索如何安全地这样做;这有点复杂,因为您需要决定如何处理队列中尚未完成的任何作业。如果这不是问题,那就很简单:.shutdown() 即可完成工作。

关于java - Java 8中等待状态线程不断增加的原因是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64049987/

相关文章:

java - 第二次尝试打开日历应用程序崩溃

java - Log4j2:如果已存在,则记录到不同的文件

java - 如何存储和修改账户余额:

c# - 数字处理线程的高效取消事件实现?

java - 使用 Java 8 Streams、map、filter、reduce 查找具有名字和姓氏的 Actor 曾工作过的电影

java - Mule 2.2.1-HF5 兼容 Java 8

java - 读取 JPG 文件直到出现某些字节

java - 如何终止子线程的父线程?

java - 涉及Swing的EDT的线程错误

java - 为什么 Arrays.stream() 不支持 char[] 唯一的数组?