简体   繁体   English

Java - 线程卡在“停放”状态

[英]Java - Thread stuck in “Park” status

I'm having trouble getting over 100 threads to run simultaneously.我无法同时运行 100 多个线程。 When I do a thread dump, I noticed that many of them are in parked status , ie当我进行线程转储时,我注意到其中许多都处于parked status ,即

parking to wait for <0x00000000827e1760> (java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject).停车等待 <0x00000000827e1760> (java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)。

The program runs fine with about 25 threads or less.该程序在大约 25 个或更少线程的情况下运行良好。 Is there a way ti identify what's causing the concurrent lock, and/or prevent it?有没有办法确定导致并发锁的原因,和/或防止它? This was running in a fixed pool size of 200 using the Executor service.这是使用 Executor 服务在 200 的固定池大小中运行的。

Apologies for the lack of code - it's proprietary and there's a lot to be changed to obfuscated it.为缺少代码道歉 - 它是专有的,有很多东西需要改变来混淆它。

The class (ConditionObject) you are referring to is used to lock objects from being accessed concurrently by multiple threads.您所指的类 (ConditionObject) 用于锁定对象不被多个线程同时访问。 The Javadoc doesn't describe the thread state you mention, but here is my guess: Javadoc没有描述您提到的线程状态,但这是我的猜测:

Your locked object is being blocked by one thread so long, that the other threads start to pile up on the lock.您锁定的对象被一个线程阻塞了很长时间,以至于其他线程开始堆积在锁上。 Once the thread holding the lock releases it, the next thread continues the aquire the lock.一旦持有锁的线程释放它,下一个线程就会继续获取锁。 Until that new thread has done his work, new threads pile up behing the lock.在那个新线程完成他的工作之前,新线程会堆积在锁后面。

If my guess is right, then could:如果我的猜测是正确的,那么可以:

  • reduce the time that each thread spends in the lock, or减少每个线程在锁中花费的时间,或
  • distribute the threads on different locked things (if your problem permits that), or将线程分配到不同的锁定对象上(如果您的问题允许),或
  • you use an implementation that doesn't require locking.您使用不需要锁定的实现。

Without knowing your problem domain, I hope that the information above is enough to point you into some direction that might be of help for you.在不知道您的问题域的情况下,我希望以上信息足以为您指明可能对您有所帮助的方向。

Are you using some sort of ThreadPoolExecutor such as the ones provided by java.util.concurrent.Executors class?您是否在使用某种ThreadPoolExecutor,例如java.util.concurrent.Executors类提供的那些? Perhaps you are facing a case of tasks being finished by silently uncaught exceptions.也许您正面临着任务被静默未捕获的异常完成的情况。 The dump fragment looks like an inactive pooled thread and one reason to get an inactive thread (which should be active) is an exception throwed up but surrounded by the default thread pool implementation.转储片段看起来像一个不活动的池线程,获得不活动线程(应该是活动的)的一个原因是抛出异常但被默认线程池实现包围。

LockSupport.park() LockSupport.park()

In thread pools, THREADS waiting for a TASK are locked out by LockSupport.park();在线程池中,等待任务的线程被LockSupport.park();锁定LockSupport.park(); . . See java.util.concurrent.locks.AbstractQueuedSynchronizer source from openjdk :请参阅来自 openjdk 的java.util.concurrent.locks.AbstractQueuedSynchronizer 源代码

public final void await() throws InterruptedException {
    // code omitted
    while (!isOnSyncQueue(node)) {
        LockSupport.park(this);
        if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
            break;
    }
    // code omitted
}

It means that the TASK which the THREAD were executing finished (abruptaly or not) and now the thread is waiting for another task to execute (see java.util.concurrent.ThreadPoolExecutor openjdk source ):这意味着线程正在执行的任务已完成(是否突然),现在线程正在等待另一个任务执行(请参阅java.util.concurrent.ThreadPoolExecutor openjdk source ):

private Runnable getTask() {
    // ...
    Runnable r = timed ?
        workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
        workQueue.take();  <== the thread is blocked here  
    // ...
}

As one can see, the thread is locked out in the call workQueue.take();可以看到,线程在调用workQueue.take();被锁定了workQueue.take(); . .

Thus, shortly, threads in "parked status" are just waiting for new tasks after the previous ones have finished.因此,很快,处于“停放状态”的线程只是在前一个任务完成后等待新任务。

Why does my task is no longer running?为什么我的任务不再运行?

The most reasonable cause of a finished task is the regular end of the run() .完成任务的最合理原因是run()的正常结束。 The task flow finishes and then the task is released by the respective owner thread.任务流结束,然后任务由各自的所有者线程释放。 Once the thread releases the task, it is ready to execute another task as long there is one.一旦线程释放任务,只要有任务,它就准备好执行另一个任务。

A straightforward way to check this scenario is by logging something in the end of the run() method:检查这种情况的一种直接方法是在run()方法的末尾记录一些内容:

class MyRunnable implements Runnable {

    public void run() {
        while(/*some condition*/) {
           // do my things
        }
        log.info("My Runnable has finished for now!");
    }
}

If log a message is not enough you can call a method of another object instead.如果记录一条消息还不够,您可以调用另一个对象的方法。

Exceptions under the wood木头下的例外

Another (most) probable cause is an uncaught exception thrown during the task execution.另一个(最)可能的原因是任务执行期间抛出的未捕获异常。 Within a thread pool, an unchecked exception like this will abruptaly stop the method execution and (surprisely) be swallowed into a java.util.concurrent.FutureTask object.在线程池中,像这样的未经检查的异常将突然停止方法执行并(出人意料地)被吞入java.util.concurrent.FutureTask对象中。 In order to avoid things like this, I use the following idiom:为了避免这样的事情,我使用以下习语:

class MyRunnable implements Runnable {
    public void run() {
        while(/*some condition*/) {
            try {
                // do my things
            } catch (Throwable throwable) {
                handle(throwable);
            }
        }
        log.info("My Runnable has finished for now!");
    }

    private void handle(Throwable throwable) {
        // ...
    }
}

or depending on the logic/performance requirements I also use:或者根据我也使用的逻辑/性能要求:

    public void run() {
        try {
            while(/*some condition*/) {
                // do my things
            }
        } catch (Throwable throwable) {
            handle(throwable);
        }
        System.out.println("My Runnable has finished for now!");
    }

The code below exemplify the issues commented here in action:下面的代码举例说明了这里评论的问题:

package mypocs;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

public class ExceptionSwallowingInThreadPoolsPoC {

  public static void main(String[] args) {

    ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);

    final Object LOCK = new Object();

    threadPoolExecutor.submit(() -> {
      while (true) {
        synchronized (LOCK) {
          System.out.println("Thread 'A' never ends");
        }
        Thread.sleep(1000L);
      }
    });

    threadPoolExecutor.submit(() -> {
      int lifespan = 3;
      while (lifespan > 0) {
    synchronized (LOCK) {
              System.out.println("Thread 'B' is living for " + lifespan + " seconds");
        }
        lifespan--;
        try {
          Thread.sleep(1000L);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
      System.out.println("Thread 'B' finished");
    });

    threadPoolExecutor.submit(() -> {
      int lifespan = 3;
      while (lifespan > 0) {
        synchronized (LOCK) {
          System.out.println("Thread 'C' is living for " + lifespan + " seconds");
        }
        lifespan--;

        if (lifespan < 1) {
          throw new RuntimeException("lifespan reached zero");
        }

        try {
          Thread.sleep(1000L);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
      System.out.println("Thread 'C' finished");
    });

    while (true) {
      try {
        Thread.sleep(1000L);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      synchronized (LOCK) {
        System.out.println("==== begin");
        System.out.println("getActiveCount: " + threadPoolExecutor.getActiveCount());
        System.out.println("getCompletedTaskCount: " + threadPoolExecutor.getCompletedTaskCount());
        System.out.println("getPoolSize: " + threadPoolExecutor.getPoolSize());
        System.out.println("==== end");
      }
    }

  }

}

The code should output something like:代码应该输出如下内容:

Thread 'A' never ends
Thread 'B' is living for 3 seconds
Thread 'C' is living for 3 seconds
Thread 'C' is living for 2 seconds
==== begin
getActiveCount: 3
getCompletedTaskCount: 0
getPoolSize: 3
==== end
Thread 'B' is living for 2 seconds
Thread 'A' never ends
==== begin
getActiveCount: 3
getCompletedTaskCount: 0
getPoolSize: 3
==== end
Thread 'C' is living for 1 seconds
Thread 'B' is living for 1 seconds
Thread 'A' never ends
Thread 'B' finished
==== begin
getActiveCount: 1
getCompletedTaskCount: 2
getPoolSize: 3
==== end
Thread 'A' never ends
Thread 'A' never ends
...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM