2016-01-21 80 views
3

我正在调查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); 
} 

我认为修改摆动不能在一个单独的线程来完成,所以我,有一个setText来改变在invokeLater点击按钮JTextField的大小。这样做应该打破单线程规则,这会不会导致死锁?

回答

2

从其他线程对Swing组件进行更改不会造成死锁您的程序(至少不是通常) - 只是JVM没有义务反映其他线程中某个线程所做状态的更改,除非有发生在之间的关系,例如​​块或访问volatile字段。 JVM可能会决定只读取一次变量的值,并且不会在当前线程中重新读取它,这意味着您的更新永远不会被绘制UI的线程看到,或者可能会在稍后不可预知的时间内更新它。

使用invokeLater插入更新到EDT确保有一个之前发生那setText和接下来的绘制操作之间

更新:正如你现在已经成功地通过移动使代码的僵局,你排队Runnable,问题是,当你试图去排队就可以了操作的EDT尚未运行。

+0

为什么在[这个](http://stackoverflow.com/questions/8865800/deadlock-when-using-settext-on-jtextarea-in-swing)问题他们得到一个类似的设置我的死锁?他们之间有什么区别 – Aequitas

+0

@Aequitas对于初学者,你没有在Swing对象(框架)上同步,然后你在Swing事件线程开始之后提交你的任务(另一个尝试在任何之前提交它Swing已经启动)。 – chrylis

+0

我看到了谢谢,我将invokeLater移入主体而不是按钮按下,现在它已经死锁。同步化的意思是什么? – Aequitas

2

在上面的示例中,您正在使用单个线程。由于大多数GUI环境都使用事件队列来操作Swing。此队列包含必须处理的内容,如点击事件,文本框编辑事件。这些都是在所谓的GUI线程上执行的。 Swing不断重绘场景并处理队列中的事件。这些事件只能在一个线程中处理,这就是为什么当您在点击处理程序中进行长时间计算(或联网)时应用程序会冻结。当您拨打SwingUtilities.invokeLater时,您的代码将被提交并放入事件队列中。当Swing有一段时间时,它会在GUI线程上执行它。

对于僵局需要具备以下条件:

  • 至少有两个线程
  • ,通过第一锁定他们
  • 锁定发生在不同的顺序在不同的线程上的资源A和B的操作

潜在的死锁例子:

Thread1: Thread2: 
lock(A)  lock(B) 
lock(B)  lock(A) <---- may deadlock here 
do stuff do stuff 
free(B)  free(A) 
free(A)  free(B) 

您的示例和您在注释中链接的示例的主要区别在于,您在此处正在主线程上创建GUI(类似于其他示例),但在用户单击之前您不调用Swing的GUI线程在按钮上。 GUI构建在主线程上,不会干扰Swing线程。在另一个例子中,GUI由两个线程并行构建。

+0

看到[这个](http://stackoverflow.com/questions/8865800/deadlock-when-using-settext-on-jtextarea-in-swing)的问题,他们有一个类似的设置使用invokeLater,但仍然设法陷入僵局。你说的为什么只有一个线程? – Aequitas

+0

@Aequitas查看我的更新回答。 –

+0

更正式地说,*必须*对死锁持有的条件是:互斥,等待,不先占和循环等待。 – ChiefTwoPencils

0

从不同线程调用Swing方法确实不明智,但不是因为死锁的风险。主要风险是:

  • 螺纹干涉
  • 内存一致性错误

根据The Event Dispatch Thread。死锁主要来自多线程中不正确的有序锁定机制。由于许多Swing对象显然没有适当的锁定,死锁并不是主要问题。