[英]truly “synchronized” method for Event Dispatch Thread
在方法上使用synced關鍵字一次只能允許一個線程執行該方法,但是EDT可以處理將同時在該方法中運行的多個“事件”。 請參見下面的示例代碼進行演示。 當您單擊測試按鈕時,輸出為:
0 before dialog, EDT=true
1 before dialog, EDT=true
(click OK button for 1 here)
1 after dialog, EDT=true
(click OK button for 0 here)
0 after dialog, EDT=true
我正在尋找的是一種僅一次允許一個EDT事件在test()方法中處於活動狀態的方法,因此輸出將是
0 before dialog, EDT=true
(click OK button for 0 here)
0 after dialog, EDT=true
1 before dialog, EDT=true
(click OK button for 1 here)
1 after dialog, EDT=true
好像有人一定已經解決了這個問題。 我認為可以編寫某種鎖定對象以在方法開始時使用,或者包裝該方法,但是由於很懶,所以寧願不要重新發明輪子。
我的測試用例:
package test1;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
public class EDTSyncTest extends javax.swing.JFrame {
private static final Object locker = new Object();
private int counter;
public EDTSyncTest() {
initComponents();
}
private synchronized void test() {
int l_id = counter++;
logit("" + l_id + " before dialog, EDT=" + SwingUtilities.isEventDispatchThread());
JOptionPane l_pane = new JOptionPane("test id " + l_id);
JDialog l_diag = l_pane.createDialog(this, "test");
l_diag.setModal(true);
l_diag.setVisible(true);
logit("" + l_id + " after dialog, EDT=" + SwingUtilities.isEventDispatchThread());
}
private void startTest() {
new Delayer().execute();
test();
}
private static void logit(String a_msg) {
System.out.println(a_msg);
}
private class Delayer extends SwingWorker<Object, Object> {
@Override
protected Object doInBackground() throws Exception {
Thread.sleep(2000);
return null;
}
@Override
protected void done() {
test();
}
}
private void initComponents() {
jButton1 = new javax.swing.JButton();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
getContentPane().setLayout(new java.awt.FlowLayout());
jButton1.setText("Test");
jButton1.setName("jButton1"); // NOI18N
jButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
jButton1ActionPerformed(evt);
}
});
getContentPane().add(jButton1);
pack();
}
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
startTest();
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new EDTSyncTest().setVisible(true);
}
});
}
protected javax.swing.JButton jButton1;
}
好的,這是我的答案,這是在millimoose支持下進行的:D
讓我們從這些觀察開始:
因此,模式對話框無法阻止擺動事件 ,否則將導致整個UI變得無響應。 那么,如何阻止而不阻止揮桿事件呢?
模態對話框運行其自己的事件分發循環 。 然后,代碼執行調用圖(在SwingWorker完成后完全在EDT線程上運行)如下所示:
-> done (process FIRST done)
-> 0/before
-> modal dialog event loop (process NEXT done)
-> 1/before
-> modal dialog event loop (TOP DIALOG)
<- OK PRESSED
<- 1/after
<- OK PRESSED
<- 0/after
<- back to normal EDT event loop
因此,模式對話框在運行時仍會以“遞歸”方式處理擺動事件 。
我剛剛弄清楚自己,但是正如@millimoose所說:
test()
方法不是並發調用的,而是遞歸調用的。
稍微修改代碼,您將看到:
logit("" + l_id + " before dialog, EDT="
+ SwingUtilities.isEventDispatchThread());
new Throwable().printStackTrace(System.out);
輸出:
0 before dialog, EDT=true
java.lang.Throwable
at EDTSyncTest.test(EDTSyncTest.java:22)
at EDTSyncTest.startTest(EDTSyncTest.java:35)
at EDTSyncTest.jButton1ActionPerformed(EDTSyncTest.java:75)
at EDTSyncTest.access$1(EDTSyncTest.java:74)
at EDTSyncTest$1.actionPerformed(EDTSyncTest.java:66)
at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
/* ... */
at java.awt.EventDispatchThread.run(Unknown Source)
1 before dialog, EDT=true
java.lang.Throwable
at EDTSyncTest.test(EDTSyncTest.java:22)
at EDTSyncTest.access$0(EDTSyncTest.java:17)
at EDTSyncTest$Delayer.done(EDTSyncTest.java:51)
at javax.swing.SwingWorker$5.run(Unknown Source)
/* ... */
at java.awt.Dialog.setVisible(Unknown Source)
at EDTSyncTest.test(EDTSyncTest.java:27)
at EDTSyncTest.startTest(EDTSyncTest.java:35)
at EDTSyncTest.jButton1ActionPerformed(EDTSyncTest.java:75)
at EDTSyncTest.access$1(EDTSyncTest.java:74)
at EDTSyncTest$1.actionPerformed(EDTSyncTest.java:66)
at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
/* ... */
at java.awt.EventDispatchThread.run(Unknown Source)
1 after dialog, EDT=true
0 after dialog, EDT=true
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.