【发布时间】:2016-05-11 07:26:43
【问题描述】:
我有一个 Java 程序,它在一个单独的(非 EDT)线程上执行一个紧密循环。尽管我认为 Swing UI 仍然应该是响应式的,但事实并非如此。下面的示例程序显示了这个问题:单击“试试我”按钮应该会在半秒后或多或少地弹出一个对话框,并且应该可以通过单击它的任何响应来立即关闭该对话框。相反,对话框需要更长的时间才能出现,和/或在单击其中一个按钮后需要很长时间才能关闭。
- 在 Linux(具有不同发行版的两台不同机器)、Windows、Raspberry Pi(仅限服务器 VM)和 Mac OS X(由另一个 SO 用户报告)上出现问题。
- Java 版本 1.8.0_65 和 1.8.0_72(都试过了)
- i7 处理器多核。 EDT 应该有足够的备用处理能力。
有没有人知道为什么 EDT 处理会被延迟,即使只有一个繁忙的线程?
(请注意,尽管Thread.sleep 调用的各种建议是问题的原因,但它不是。它可以被删除并且问题仍然可以重现,尽管它出现的频率略低并且通常表现出第二个上述行为 - 即无响应 JOptionPane 对话框而不是延迟对话框出现。此外,睡眠调用没有理由让给其他线程,因为如上所述有备用处理器内核 ; 在调用 sleep 之后,EDT 可以继续在另一个内核上运行。
import java.awt.EventQueue;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class MFrame extends JFrame
{
public static void main(String[] args)
{
EventQueue.invokeLater(() -> {
new MFrame();
});
}
public MFrame()
{
JButton tryme = new JButton("Try me!");
tryme.addActionListener((e) -> {
Thread t = new Thread(() -> {
int a = 4;
for (int i = 0; i < 100000; i++) {
for (int j = 0; j < 100000; j++) {
a *= (i + j);
a += 7;
}
}
System.out.println("a = " + a);
});
t.start();
// Sleep to give the other thread a chance to get going.
// (Included because it provokes the problem more reliably,
// but not necessary; issue still occurs without sleep call).
try {
Thread.sleep(500);
}
catch (InterruptedException ie) {
ie.printStackTrace();
}
// Now display a dialog
JOptionPane.showConfirmDialog(null, "You should see this immediately");
});
getContentPane().add(tryme);
pack();
setVisible(true);
}
}
更新:该问题仅出现在服务器虚拟机上(但请参阅进一步更新)。指定客户端 VM(-client java 可执行文件的命令行参数)似乎可以抑制问题(update 2)在一台机器上而不是另一台机器上。
更新 3:单击按钮后,我看到 Java 进程的处理器使用率为 200%,这意味着有 2 个处理器内核已完全加载。这对我来说根本没有意义。
更新 4:也出现在 Windows 上。
更新 5: 使用调试器 (Eclipse) 被证明是有问题的;调试器似乎无法停止线程。这是非常不寻常的,我怀疑 VM 中存在某种活锁或竞争条件,所以我向 Oracle 提交了一个错误(审查 ID JI-9029194)。
更新 6: 我找到了my bug report in the OpenJDK bug database。 (我没有被告知它已被接受,我不得不搜索它)。那里的讨论最有趣,并且已经阐明了可能导致此问题的原因。
【问题讨论】:
-
这是
sleep。睡眠调用正在让步给繁忙的线程。并且 sleep/wait 只保证“至少”在它们返回时已经过了请求的时间。 -
@VGR 我不这么认为。你试过了吗?
-
是的。当我注释掉睡眠时,JOptionPane 立即出现。 (Linux amd64,四核。)
-
@VGR 立即出现,但是否响应?
-
@davmac 清晨观察,耐心不是特别高:P
标签: java multithreading swing