我正在调查 setText 上的死锁问题,但我需要先学习和理解死锁。为此,我创建了一个简短的程序来尝试复制更大范围内可能发生的事情,但我不确定为什么我的小程序永远不会死锁。
这是我的学习计划:
public static void main(String[] a)
{
JFrame frame = new JFrame();
final JTextField p = new JTextField("start");
JButton btn = new JButton("button");
btn.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
SwingUtilities.invokeLater(new Runnable(){
@Override
public void run(){
p.setText(String.valueOf(System.nanoTime()));
}
});
}
});
frame.getContentPane().setLayout(new FlowLayout());
frame.getContentPane().add(p);
frame.getContentPane().add(btn);
frame.setSize(400, 400);
frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
我认为对 swing 的修改不能在单独的线程中完成,所以我有一个 setText 来更改 invokeLater
中单击按钮时的 JTextField。这样做应该打破单线程规则,这不会导致死锁吗?
最佳答案
从其他线程更改 Swing 组件不会死锁您的程序(至少通常不会)——只是 JVM 没有义务反射(reflect)在一个线程中所做的状态更改在其他线程中,除非存在 happens-before 关系,例如 synchronized
block 或访问 volatile
字段。 JVM 可能决定只读取一次变量的值并且永远不会在当前线程中重新读取它,这意味着您的更新永远不会被绘制 UI 的线程看到,或者它可能会在以后某个不可预测的时间更新它.
使用 invokeLater
将更新插入 EDT 可确保 happens-before 在 setText
和下一个绘制操作之间。
更新:由于您现在已经通过移动 Runnable
队列的位置成功地使代码死锁,问题是 EDT 尚未运行时您尝试将其上的操作排队。
关于java - 为什么这段代码不会死锁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34914800/