2012-05-17 57 views
1

我正在使用java.net.Authenticator創建阻塞對話框,該對話框在用戶第一次通過代理建立任何連接時請求代理登錄名/密碼。 Authenticator工作得很好,但當我嘗試同步顯示輸入對話框的方法時,我遇到了一些奇怪的問題。事件調度線程內部同步問題

這裏的問題是我發現的一個抽象的工作代碼示例:

private static JFrame frame; 

public static void main (String[] args) 
{ 
    frame = new JFrame ("Frame"); 
    frame.add (new JLabel ("This is main application")); 
    frame.setSize (500, 500); 
    frame.setLocationRelativeTo (null); 
    frame.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE); 
    frame.setVisible (true); 

    // Cycling thread 
    new Thread (new Runnable() 
    { 
     public void run() 
     { 
      while (true) 
      { 
       // Opening new dialog in a separate event dispatch thread 
       SwingUtilities.invokeLater (new Runnable() 
       { 
        public void run() 
        { 
         showSomeLockingDialog(); 
        } 
       }); 

       // Wait 3 seconds before next window 
       try 
       { 
        Thread.sleep (3000); 
       } 
       catch (InterruptedException e) 
       { 
        e.printStackTrace(); 
       } 
      } 
     } 
    }).start(); 
} 

private static final Object lock = new Object(); 

private static void showSomeLockingDialog() 
{ 
    synchronized (lock) 
    { 
     // Output to see that this method is not finished yet 
     System.out.println ("Method start"); 

     // Modal thread-blocking dialog 
     JDialog dialog = new JDialog (frame, "Lock"); 
     dialog.add (new JLabel ("This should be blocking other dialogs")); 
     dialog.pack(); 
     dialog.setLocationRelativeTo (null); 
     dialog.setModal (true); 
     dialog.setVisible (true); 

     // Output to see that this method is not finished yet 
     System.out.println ("Method end"); 
    } 
} 

所以基本上:

  1. 有一個明顯的主框架(實際上,只是爲了讓JVM運行)
  2. 有循環線程請求每個週期中的showSomeLockingDialog()方法
  3. 方法在「鎖定」對象上同步
  4. 有一個在方法控制檯輸出開始和結束

所以,如果你運行這個例子,你會看到,每個週期的新對話框彈出忽略同步,即使您不關閉先前的對話框。我也嘗試了簡單的方法同步,但它具有相同的效果。如果我們改變我們稱之爲showSomeLockingDialog方式

一切都在變化()位:

new Thread (new Runnable() 
    { 
     public void run() 
     { 
      showSomeLockingDialog(); 
     } 
    }).start(); 

(只使用一個單獨的線程,而不是調用事件調度線程內法)

這樣一切正常我期待它的工作方式 - 新的對話調用被阻止,直到之前調用的那個被關閉。

而這很奇怪 - 事件調度線程的特殊之處在於同步被忽略了嗎?

或者如果它實際上是一個錯誤 - 是否有任何解決方法? 也許我失去了一些東西......巨大

的幾點思考:在我看來是模態對話框調用setVisible方法充當不同的事件調度線程內(否則它會阻礙整個界面如果從那裏調用)。但如何影響同步...

P.S.不,我不能只在我的具體情況下使用第二個(工作)的例子,因爲我不是在我想要的地方調用該方法 - 它從隨機地點調用,主要來自標準的JDK類(當任何資源從網上下載 - 在JLabel中的圖像,一些URL輸入流或其他任何東西)。

回答

2

從Dialog的setVisible javadoc documentation

It is OK to call this method from the event dispatching thread because 
the toolkit ensures that other events are not blocked while this method 
is blocked. 

,並基於該Java的synchronized塊是重入的,以下是正在發生的事情對每個invokeLater的:

  1. 調度線程調用showSomeLockingDialog
  2. 取得鎖定或重新進入
  3. 打開窗口 - >阻止,直到關閉對話框

由於阻塞只是爲了setVisible而不是其他事件(即,其他invokeLaters),那麼你會得到指定的行爲。

+0

感謝您的文檔鏈接,似乎我對setVisible方法的猜測是正確的。既然我不能離開這個方法(在從對話框中獲取信息之前),也不能用別的東西鎖定它(它的EDT,所以如果我鎖定它 - 只要鎖被激活,接口就會鎖住) - 我只能創建我的自己的同步「邏輯」爲這個具體情況,對嗎? –

+0

你對調度線程是正確的。你應該避免對它進行長時間的操作或阻止它。看起來你需要自己做同步邏輯。 – henryabra

+0

問題是我應該從EDT調用的方法中返回授權令牌。我無法阻止它(意味着我不能再等待早先完成的這種方法的另一個調用),因爲它的EDT和阻止它會凍結整個界面。我甚至無法想象在這種情況下該怎麼做......到目前爲止,我只是在顯示授權對話框時顯示的所有其他調用返回null,而不是顯示多個auth對話框(因此所有其他連接可能會因接收而失敗空令牌)。 –