java - Thread.State : WAITING (parking) vs BLOCKED at sun. misc.Unsafe.park() 有什么区别

标签 java multithreading performance threadpool hazelcast

我有一个连接到 Hazelcast 的应用程序。最近我发现对 hazelcast 的请求最终开始变得无响应,因此,我对 Hazelcast 进程进行了线程转储。在分析来自开发和生产环境的线程转储时,我发现池中等待任务的线程在不同的环境中处于不同的状态。

在生产服务器上,线程被阻塞(500 个中有 337 个)。 在开发环境中,没有线程被阻塞(在 60 个线程中,50% 为可运行,50% 为等待)。

那些阻塞线程是否正在等待某些线程无限期持有的同步块(synchronized block)? 500 个线程是否过多(我收到一些分析器的警告)?这会导致我的应用程序变得无响应吗?

这种状态的可能原因是什么以及如何解决?

线程转储(生产):

Thread 120713: (state = BLOCKED)
     - sun.misc.Unsafe.park(boolean, long) @bci=0 (Compiled frame; information may be imprecise)
     - java.util.concurrent.ForkJoinPool.awaitWork(java.util.concurrent.ForkJoinPool$WorkQueue, int) @bci=350, line=1824 (Compiled frame)
     - java.util.concurrent.ForkJoinPool.runWorker(java.util.concurrent.ForkJoinPool$WorkQueue) @bci=44, line=1693 (Interpreted frame)
     - java.util.concurrent.ForkJoinWorkerThread.run() @bci=24, line=157 (Interpreted frame)

Thread 120743: (state = BLOCKED)
    - sun.misc.Unsafe.park(boolean, long) @bci=0 (Compiled frame; information may be imprecise)
    - java.util.concurrent.locks.LockSupport.park(java.lang.Object) @bci=14, line=175 (Compiled frame)
    - java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await() @bci=42, line=2039 (Compiled frame)
    - java.util.concurrent.LinkedBlockingQueue.take() @bci=29, line=442 (Compiled frame)
    - java.util.concurrent.ThreadPoolExecutor.getTask() @bci=149, line=1074 (Compiled frame)

Thread 120743: (state = BLOCKED)
    - sun.misc.Unsafe.park(boolean, long) @bci=0 (Compiled frame; information may be imprecise)
    - java.util.concurrent.locks.LockSupport.park() @bci=5, line=304 (Compiled frame)
    - com.hazelcast.internal.util.concurrent.MPSCQueue.takeAll() @bci=83, line=231 (Compiled frame)
    - com.hazelcast.internal.util.concurrent.MPSCQueue.take() @bci=12, line=153 (Compiled frame)
    - com.hazelcast.client.spi.impl.ClientResponseHandlerSupplier$ResponseThread.doRun() @bci=17, line=164 (Compiled

Thread 128753: (state = BLOCKED)
    - sun.misc.Unsafe.park(boolean, long) @bci=0 (Compiled frame; information may be imprecise)
    - java.util.concurrent.locks.LockSupport.parkNanos(java.lang.Object, long) @bci=20, line=215 (Compiled frame)
    - java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(long) @bci=78, line=2078 (Compiled frame)
    - java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take() @bci=124, line=1093 (Compiled frame)
    - java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take() @bci=1, line=809 (Compiled frame)

来自开发环境的线程转储:

java.lang.Thread.State: TIMED_WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x00000006c1a1bc38> (a java.util.concurrent.SynchronousQueue$TransferStack)
        at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215)
        at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:460)
        at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:362)
        at java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:941)

最佳答案

Thread states - 这里是线程状态的一点解释。

NEW The thread has not yet started.

RUNNABLE The thread is executing in the JVM.

BLOCKED The thread is blocked waiting for a monitor lock.

WAITING The thread is waiting indefinitely for another thread to perform a particular action.

TIMED_WAITING The thread is waiting for another thread to perform an action for up to a specified waiting time.

TERMINATED The thread has exited.

BLOCKED 状态是否会在同一线程中长时间存在,这应该是令人担忧的。 这当然取决于您的情况 - 您如何处理数据、如何创建线程(和线程池)、您的关键部分是什么以及所有这些部分如何相互交互。

生产的单个线程转储是不够的 - 您应该进行多个转储和 - 比较发生的事情和 - 线程运行/等待多长时间 - 这是在高负载时发生还是在高负载后发生 - 你的线程数是否会随着时间的推移而增加,等等。

因此,无法判断在这个特定时间点 500 个阻塞线程是好是坏,但可以肯定的是,这是令人担忧的。一个线程大约需要 2MB 来初始化和分配,所以它是 1GB 的内存。

很可能有一些关键部分被某些线程占用,从而导致您的问题和应用程序无响应。您可能会使用阻塞方法等从队列中读取一些非常复杂的情况。

可能的行动方案:

  • 进行几次转储并进行比较 - 发生了什么变化?哪些线程仍然被阻塞?
  • 检查您是否可以在转储的堆栈跟踪中查明阻塞线程中的调用(仅是您的包前缀或 java/hazelcast 的包)。
  • 使用跟踪工具(flight-recorder/jvisualvm)检查线程的增长情况以及线程(被阻塞的)创建时间 - 应用此时正在做什么?
  • 根据阻塞调用和同步方法/使用的潜在误用分析您的代码库。
  • 在达到限制时检查线程池的最大大小和工作队列的实现和策略(例如,了解 RejectedExecutionHandler 的实现)

关于java - Thread.State : WAITING (parking) vs BLOCKED at sun. misc.Unsafe.park() 有什么区别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62293140/

相关文章:

java - 如何在 MySQL 中创建不重复的随机用户 ID?

VB.NET 如何提供最佳性能 "Select case"或 IF... ELSEIF ... ELSE... END IF

java - JVM 是 32 位还是 64 位?

java - 在单元测试中模拟/ stub RuntimeException

java - 增加线程数会降低 java 的整体性能吗?

java - 为什么这段代码是顺序执行的?

windows - 为什么我的 Ruby 线程演示不使用两个内核?

Java 多线程 - 使用 Fork-Join 方法在列表中查找最大元素

java - 使用包含参数的构造函数从类名创建 Java 对象

java - 并发 api 的 AbstractQueuedSynchronizer 构建 block 如何没有任何同步?