2016-01-21 76 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對象顯然沒有適當的鎖定,死鎖並不是主要問題。