【问题标题】:RUNNABLE Thread.State but in Object.wait()RUNNABLE Thread.State 但在 Object.wait()
【发布时间】:2015-02-20 14:44:38
【问题描述】:

我已经提取了我的容器进程的 JStack 并让线程在那里运行,并使用以下按 Thread.state 分组的分布:

count    thread state
   67    RUNNABLE
    1    TIMED_WAITING (on object monitor)
    8    TIMED_WAITING (parking)
    4    TIMED_WAITING (sleeping)
    3    WAITING (on object monitor)
   17    WAITING (parking)

对于可运行的线程,我有以下描述:

"http-bio-8080-exec-55" daemon prio=10 tid=0x000000002cbab300 nid=0x642b in Object.wait() [0x00002ab37ad11000]
   java.lang.Thread.State: RUNNABLE
    at com.mysema.query.jpa.impl.JPAQuery.<init>(JPAQuery.java:44)
    at net.mbppcb.cube.repository.TransactionDaoImpl.findByBusinessId(TransactionDaoImpl.java:73)
    at sun.reflect.GeneratedMethodAccessor76.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:317)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:155)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
    ...

如上所示,处于 RUNNABLE 状态的线程数随着时间的推移而增加,并且似乎处于挂起状态。如果他们假设被阻止,他们不应该处于 BLOCKED 状态吗?或者他们应该处于 WAITING 状态?有 RUNNABLE 线程但在 Object.wait() 中不是很奇怪吗?

更新 1

我可以在文档中看到:

处于可运行状态的线程正在 Java 虚拟中执行 机器,但它可能正在等待来自操作的其他资源 处理器等系统。

我怎样才能知道线程在等待什么?

【问题讨论】:

  • Object.wait() 中的线程应该有Thread.State.WAITING,而不是BLOCKED。也就是说,我不知道为什么会是RUNNABLE
  • 你是对的,我的错。但这种奇怪的状态会不会与我的 JVM 版本和操作系统版本有关?可能是两者结合的奇怪错误?
  • Object.wait() 中线程的其余堆栈跟踪是什么?
  • @DennisW 线程在调用o.wait() 的事实并不像你想象的那样紧密耦合到它的状态。当事件发出信号时,线程的状态将从WAITING 更改为RUNNABLE,但线程仍将处于o.wait() 调用中。然后它会经历其他的状态变化:它最终会运行,然后它可能会在尝试重新获取锁时再次被阻塞,然后它会第二次变为RUNNABLE,最后它会得到再次运行,它将从调用中返回。
  • @KristofferE:刚刚添加了有关堆栈跟踪的其他信息

标签: java multithreading


【解决方案1】:

这似乎是class initialization deadlock

JPAQuery构造函数正在等待一个依赖类的初始化,大概是JPAProvider

    public JPAQuery(EntityManager em) {
        super(em, JPAProvider.getTemplates(em), new DefaultQueryMetadata());
    }

当从静态初始化程序引用子类时,typical bug 可能会导致此类死锁。如果您分享其他线程堆栈的详细信息,我们可能会找出哪个线程持有类锁。

那为什么线程处于RUNNABLE 状态呢?

嗯,这是 HotSpot JVM 内部的一个混乱。类初始化过程是在 VM 运行时而不是在 Java 领域中实现的,并且类锁是在本地获取的。似乎是线程状态没有改变的一个原因,但我想这种行为也应该在 JVM 中修复。

【讨论】:

  • mysema 的问题正是这个(类初始化死锁),这是在 mysema 上开的票:github.com/querydsl/querydsl/issues/1237https://github.com/…
  • 谢谢!我现在在几个场合看到 Object.wait() 中的 RUNNABLE 线程时被打扰了。我刚刚验证了您所描述的实际上是正在发生的事情。
【解决方案2】:

Oracle Thread.State documentation 指定处于阻塞状态的线程正在等待监视器锁进入同步块/方法或调用后重新进入同步块/方法。 看起来没有线程处于阻塞模式。

【讨论】:

    【解决方案3】:

    如果所有 Runnable 线程在数据库操作中明显被阻塞,我建议使用数据库监控/诊断工具来探索原因。之后,可能会调查您的数据库代码以发现诸如未提交的事务、错误处理的异常导致未关闭的资源等问题。

    Java 线程转储可能已经为您提供了他们在这一点上所能提供的所有信息 - 一个指示下一步从哪里开始查找的指针。

    【讨论】:

    • 这是一个有效的观点,但是,如果它被查询阻塞,我希望调用堆栈中的数据库驱动程序调用它吗?这里奇怪的是,这发生在JPAQuery.&lt;init&gt;,让我知道你的想法。
    【解决方案4】:

    "如上所示处于 RUNNABLE 状态的线程数随着 时间,好像挂了。”

    RUNNABLES 的数量会根据执行“com.mysema.query.jpa.impl.JPAQuery”方法的线程数量而增加。在进行此线程转储时。这个方法实际上是 JPAQuery 类的构造函数 - 用 "init" 表示。您可能需要调查构造函数中的代码以及对 JPA 实现的后续调用。

    【讨论】:

    • 当我评论它随着时间的推移而上升时,这意味着线程将在给定点(JPAQuery 的构造函数)停止并且不会返回到池中,如果我采取更多的线程转储线程将在同一点
    【解决方案5】:

    Object.wait() 只调用Object.wait(0)(零表示没有超时)。 Object.wait(long)的实现是:

    public final native void wait(long timeout) throws InterruptedException;
    

    本地框架中的所有线程都是RUNNABLE,因为 JVM 不知道(不“管理”,因此它是“本地”框架)调用的状态。

    【讨论】:

      猜你喜欢
      • 2011-09-28
      • 2012-05-28
      • 1970-01-01
      • 2016-03-04
      • 2012-02-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多