EventQueue.isDispatchThread() 中的无限循环

Posted

技术标签:

【中文标题】EventQueue.isDispatchThread() 中的无限循环【英文标题】:Infinite loop in EventQueue.isDispatchThread() 【发布时间】:2015-06-20 03:07:46 【问题描述】:

我有一个 Java 程序占用 100% cpu,但似乎什么也没做。

如果我进行线程转储,则有 4 个线程(在 5 个线程池中)等待锁定。

"Incoming WorkPool 5" - Thread t@363
   java.lang.Thread.State: WAITING
    at sun.misc.Unsafe.park(Native Method)
    - waiting to lock <7212149b> (a java.util.concurrent.locks.ReentrantLock$NonfairSync) owned by "Incoming WorkPool 3" t@354
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:834)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:867)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1197)
    at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:214)
    at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:290)
    at java.awt.EventQueue.isDispatchThreadImpl(EventQueue.java:1019)
    at java.awt.EventQueue.isDispatchThread(EventQueue.java:1014)

他们正在等待的线程是 RUNNABLE

"Incoming WorkPool 3" - Thread t@354
   java.lang.Thread.State: RUNNABLE
    at java.awt.EventQueue.isDispatchThreadImpl(EventQueue.java:1024)
    at java.awt.EventQueue.isDispatchThread(EventQueue.java:1014)

这是JDK 7.0.25,所以似乎有一个线程卡住了

EventQueue next = eq.nextQueue;
while (next != null) 
    eq = next;
    next = eq.nextQueue;

有两个 AWT EventQueue 线程,试图获取相同的 pushpoplock。

VM 作为服务运行,所以它不应该尝试做 AWT 的事情,但它是由我正在使用的库完成的。

有什么想法吗?我可以防止这种情况发生吗?

谢谢!

【问题讨论】:

1.你听说过SecondaryLoop吗,2。但是“占用100% cpu,但似乎什么也没做”。谈论 JProfiler,3. 没有 SSCCE/MCVE 无法回答,4. java.awt.EventQueue.isDispatchThreadImpl(EventQueue.java:1019) talking about isEventDispatchThread returns false,或者在 EDT 中执行的事件在那里没有业务 5. 不知道,没有来自当前 EDT 的事件或来自 RepaintManager 的异常 1) 我之前没有听说过 SecondaryLoop。我已经查过了,但我自己不使用 AWT,它是我使用的一个调用该方法的库。 2)我没有使用过JProfiler,我使用过JVisualVM,它为我提供了我展示过的sn-ps的threaddump。 3)不幸的是,我无法复制它。这是我在生产中遇到的一个问题,我只有线程转储,所以我无法提供 SSCCE。 4-5) 恐怕我不懂这些。 谁将 eq.nextQueue 设置为 null?如果没有人设置它,那么循环将无限运行并且 CPU 100% 是可能的。如果是,并且如果它是由其他线程完成的,那么 sq.nextQueue 应该是易变的。如果不是,该线程可能不会选择该值,因为该线程可以缓存 eq.nextQueue 的值,其中循环将再次无限运行并且 CPU 100% 可能。 据我所知,它被初始化为 null 并且仅在使用 java.awt.EventQueue.push(EventQueue newEventQueue) 时设置。 为什么有两个 AWT 事件队列?应该只有一个。 【参考方案1】:

您的问题是死锁问题(see wikipeida)。

正如您在上面看到的,您的两个 EventQueue(此处为 R1 和 R2)处于死锁状态 - 它们中的每一个都占用了一个资源,并且在 另一个确实要求了其他资源。两人都在无休止地等待着对方。

你可以用不同的方法解决这个问题:

尝试改变图书馆,图书馆不应该尝试做awt是对的 如果它不是与 awt 密切相关的库的话。 像 github 这样的平台上有很多库,我很确定你会发现 另一个库来替换导致错误的库。

如果您能够编辑代码以添加监控,那么您就是 也可以防止任何死锁。

synchronized(lock)
EventQueue next = eq.nextQueue;
while (next != null) 
    eq = next;
    next = eq.nextQueue;

lock.notifyAll();

【讨论】:

上面的代码是 Java SDK (java.awt.EventQueue.isDispatchThreadImpl(EventQueue.java:1024)) 的一部分,我无法或不想更改该代码。 【参考方案2】:

有没有可能push(EventQueue newEventQueue) 被您的应用程序调用并推送相同的事件队列?如果是,那么,this 和它的nextQueue 将是相同的对象,它们将在无限循环中运行,消耗 CPU 到 100%。

从堆栈跟踪可以看出至少有一个线程正在运行。所以这不是死锁的问题。

从 100% CPU 消耗提示及其状态为 RUNNABLE 可以看出,它正在执行无限循环。

代码可以进入无限循环当且仅当nextQueue 的值已经在链中(或this)。这很可能是一个应用程序问题。谢谢。

【讨论】:

我从来没有想过这个,但是我使用的库确实有可能做这个 EventQueue.push。它不是一个开源库,所以我得和他们核实一下。

以上是关于EventQueue.isDispatchThread() 中的无限循环的主要内容,如果未能解决你的问题,请参考以下文章