首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >卡在"Park“状态

卡在"Park“状态
EN

Stack Overflow用户
提问于 2018-02-04 22:17:05
回答 2查看 4.6K关注 0票数 1

我很难让超过100个线程同时运行。当我做线程转储时,我注意到很多线程都在parked status中,即

停车等候(java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject). <0x00000000827e1760>

该程序运行良好,大约25个线程或更少。有没有一种方法可以识别导致并发锁的原因和/或阻止它?这是在使用Executor服务的固定池大小200中运行的。

对于代码的缺乏表示歉意--它是专有的,并且有很多地方需要修改以混淆它。

EN

回答 2

Stack Overflow用户

发布于 2020-01-21 23:29:11

您是否在使用某种ThreadPoolExecutor,如java.util.concurrent.Executors类提供的那种?也许你正面临着一种情况,那就是任务是通过秘密的异常来完成的。转储片段看起来像一个非活动池线程,获得非活动线程(应该是活动线程)的一个原因是抛出的异常,但被默认线程池实现包围。

LockSupport.park()

在线程池中,等待任务的线程被LockSupport.park();锁定。参见java.util.concurrent.locks.AbstractQueuedSynchronizer 来源: openjdk

代码语言:javascript
运行
复制
public final void await() throws InterruptedException {
    // code omitted
    while (!isOnSyncQueue(node)) {
        LockSupport.park(this);
        if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
            break;
    }
    // code omitted
}

这意味着线程正在执行的任务已经完成(不管是否突然),现在线程正在等待另一个任务的执行(请参阅java.util.concurrent.ThreadPoolExecutor openjdk源):

代码语言:javascript
运行
复制
private Runnable getTask() {
    // ...
    Runnable r = timed ?
        workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
        workQueue.take();  <== the thread is blocked here  
    // ...
}

可以看到,线程被锁在调用workQueue.take();中。

因此,很快,处于“已停放状态”的线程只是在前面的任务完成后等待新的任务。

为什么我的任务不再运行?

完成任务最合理的原因是run()的规则端。任务流完成,然后由相应的所有者线程释放任务。一旦线程释放了任务,只要有一个任务,它就可以执行另一个任务。

检查此场景的一种简单方法是在run()方法的末尾记录某些内容:

代码语言:javascript
运行
复制
class MyRunnable implements Runnable {

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

如果只记录一条消息是不够的,则可以调用另一个对象的方法。

木材下的例外

另一个(大多数)可能的原因是在任务执行期间抛出的异常。在线程池中,这样未经检查的异常将突然停止方法的执行,并(令人惊讶地)被吞没到java.util.concurrent.FutureTask对象中。为了避免出现这种情况,我使用了以下成语:

代码语言:javascript
运行
复制
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) {
        // ...
    }
}

或者取决于我还使用的逻辑/性能要求:

代码语言:javascript
运行
复制
    public void run() {
        try {
            while(/*some condition*/) {
                // do my things
            }
        } catch (Throwable throwable) {
            handle(throwable);
        }
        System.out.println("My Runnable has finished for now!");
    }

下面的代码举例说明了在行动中评论的问题:

代码语言:javascript
运行
复制
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");
      }
    }

  }

}

代码应该输出如下所示:

代码语言:javascript
运行
复制
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
...
票数 4
EN

Stack Overflow用户

发布于 2018-02-04 22:51:02

您所引用的类(ConditionObject)用于锁定被多个线程并发访问的对象。Javadoc没有描述您提到的线程状态,但我的猜测是:

锁定的对象被一个线程阻塞的时间太长,其他线程开始堆积在锁上。一旦持有锁的线程释放了锁,下一个线程就会继续锁定。直到那根新的线完成他的工作,新的线程堆积在锁上。

如果我的猜测是对的,那就可以:

  • 减少每个线程在锁中的时间,或者
  • 将线程分配到不同的锁定对象上(如果问题允许的话),或者
  • 您使用不需要锁定的实现。

不知道你的问题领域,我希望上面的信息足以为你指出一些可能对你有帮助的方向。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48613567

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档