EDTはいつ開始されますか?どのコード行がそれを担当していますか?
私の推測では、「someSwingComponent.setVisible(true)」でうまくいくと思いますが、よくわかりません。
ありがとう!
EDTはいつ開始されますか?どのコード行がそれを担当していますか?
私の推測では、「someSwingComponent.setVisible(true)」でうまくいくと思いますが、よくわかりません。
ありがとう!
Swingの内部動作はJVM固有です。異なるJVMは、異なる基準に基づいてイベントディスパッチスレッド(EDT)を開始します。一般的には:
EDTは、最初のを受信したときに開始されます
AWTEvent
。
以下のスタックトレースは、この点を再確認します。たとえば、次のmain
方法を考えてみましょう。
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setVisible(true);
}
上記の例では、EDTの開始を担当するコード行は次のとおりです。frame.setVisible(true);
上記のmain
メソッドは、2つの異なるJVMで実行されました。ブレークポイントがに配置されましたEventQueue.initDispatchThread
。ブレークポイントに到達すると、次のスタックトレースが記録されました。
AWT-AppKit
スレッドでのMacのJDKの使用:
EventQueue.initDispatchThread() line: 906
EventQueue.wakeup(boolean) line: 1109
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method]
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25
Method.invoke(Object, Object...) line: 597
SunToolkit.wakeupEventQueue(EventQueue, boolean) line: 348
PostEventQueue.postEvent(AWTEvent) line: 2137
SunToolkit.postEvent(AppContext, AWTEvent) line: 583
SunToolkit.executeOnEventHandlerThread(PeerEvent) line: 654
SunToolkit.executeOnEventHandlerThread(Object, Runnable) line: 631
EventFactoryProxy.windowMoved(CWindow) line: 89
スレッドでのOracleのJDKforWindowsの使用main
:
java.awt.EventQueue.initDispatchThread() line: 861
java.awt.EventQueue.postEventPrivate(java.awt.AWTEvent) line: 199
java.awt.EventQueue.postEvent(java.awt.AWTEvent) line: 180
javax.swing.RepaintManager.scheduleProcessingRunnable(sun.awt.AppContext) line: 1369
javax.swing.RepaintManager.nativeAddDirtyRegion(sun.awt.AppContext, java.awt.Container, int, int, int, int) line: 548
javax.swing.SwingPaintEventDispatcher.createPaintEvent(java.awt.Component, int, int, int, int) line: 45
sun.awt.windows.WFramePeer(sun.awt.windows.WComponentPeer).postPaintIfNecessary(int, int, int, int) line: 741
sun.awt.windows.WFramePeer(sun.awt.windows.WComponentPeer).handlePaint(int, int, int, int) line: 736
sun.java2d.d3d.D3DScreenUpdateManager.repaintPeerTarget(sun.awt.windows.WComponentPeer) line: 274
sun.java2d.d3d.D3DScreenUpdateManager.createScreenSurface(sun.awt.Win32GraphicsConfig, sun.awt.windows.WComponentPeer, int, boolean) line: 175
...
sun.awt.windows.WToolkit.createFrame(java.awt.Frame) line: 383
javax.swing.JFrame(java.awt.Frame).addNotify() line: 460
javax.swing.JFrame(java.awt.Window).show() line: 859
javax.swing.JFrame(java.awt.Component).show(boolean) line: 1584
javax.swing.JFrame(java.awt.Component).setVisible(boolean) line: 1536
javax.swing.JFrame(java.awt.Window).setVisible(boolean) line: 842
Example.main(java.lang.String[]) line: 113
Macでは、への呼び出しPostEventQueue.postEvent(AWTEvent)
が行われます。同様に、Windowsでは、への呼び出しjava.awt.EventQueue.postEvent(java.awt.AWTEvent)
が行われます。どちらも最終的にはを呼び出しますEventQueue.initDispatchThread
。
別の例として、次のmain
方法を検討してください。
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
System.out.println("Start!");
}
});
}
main
スレッドでのMacのJDKの使用:
EventQueue.initDispatchThread() line: 906 [local variables unavailable]
EventQueue.postEventPrivate(AWTEvent) line: 227
EventQueue.postEvent(AWTEvent) line: 208
EventQueue.invokeLater(Runnable) line: 1048
SwingUtilities.invokeLater(Runnable) line: 1267
Example.main(String[]) line: 31
スレッドでのOracleのJDKforWindowsの使用main
:
java.awt.EventQueue.initDispatchThread() line: 861
java.awt.EventQueue.postEventPrivate(java.awt.AWTEvent) line: 199
java.awt.EventQueue.postEvent(java.awt.AWTEvent) line: 180
java.awt.EventQueue.invokeLater(java.lang.Runnable) line: 999
javax.swing.SwingUtilities.invokeLater(java.lang.Runnable) line: 1267
の呼び出しSwingUtilties.invokeLater
は、EDTを開始する責任があります。ここでも、への呼び出しEventQueue.postEvent(AWTEvent)
が行われます。
を呼び出すだけでsomeSwingComponent.setVisible(true)
EDTが開始されるわけではありません。たとえば、次のメソッドを実行してもスレッドmain
は作成されません。AWT-Event-Queue-0
public static void main(String[] args) {
JLabel label = new JLabel();
label.setVisible(true);
}
もちろん、EDTについてはオンラインで多くのリソースがあります。
編集:あなたたちは正しいです。EDTは起動時に直接開始されません。私はいくつかのデバッグを行いました、そしてこれは私が見つけたものです:
コンポーネントがToolkit.getEventQueue()を呼び出してイベントキューへのアクセスを要求するたびに、イベントディスパッチスレッドが遅延開始されます。これは、Component.show()が呼び出されたときに実行できます(Component.setVisible()と同じ)が、Component.repaint()のようなこの初期化をトリガーできる他の呼び出しもあります。イベントキューへの参照が取得されると、EventQueue.postEvent()を使用してそれにジョブを追加できます。このメソッドは、EDTが存在するかどうかを確認し、存在しない場合は、initDispatchThread()を使用して作成します。
起動を防ぐ唯一の方法は、「-Djava.awt.headless = true」フラグを使用して、JVMをヘッドレスモード(AWTをすべて一緒に無効にする)で起動することです。しかし、それは基本的にあなたがそれと持つことができる唯一の低レベルの相互作用です。
コンポーネントのsetVisibleメソッドは、常にEDTで呼び出す必要があります(Swing / AWTコンポーネントに加える他の変更と同じように)。EDTを使用するには、JavaにEDTでコードを実行するように指示します。これを行う最も簡単な方法は、SwingUtilities.invokeLater()を使用することです。これにより、スレッド(Runnable実装)がEDTから実行されるようにスケジュールされます。これは、開発者がEDTと行う必要がある唯一の種類の対話です。スレッドの一時停止や中止など、EDTとの低レベルの相互作用はありません。
あなたは正しいsetVisibleでEDTを開始するAWT/Swingコンテナ、安全でない方法
初期スレッドは最も安全な方法です
すべてのイベントが現在のEDTで行われる場合、isDispatchThreadはfalseを返します
isDispatchThreadがfalseを返す場合、SwingスレッドセーフメソッドはEDTを存続させることができます。最も安全な方法は、invokeLater()からそれを呼び出すことです。
テスト用のコード
import java.awt.Color;
import java.awt.EventQueue;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
public class IsThereEDT {
private ScheduledExecutorService scheduler;
private AccurateScheduledRunnable periodic;
private ScheduledFuture<?> periodicMonitor;
private int taskPeriod = 30;
private SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
private Date dateRun;
private JFrame frame1 = new JFrame("Frame 1");
public IsThereEDT() {
scheduler = Executors.newSingleThreadScheduledExecutor();
periodic = new AccurateScheduledRunnable() {
private final int ALLOWED_TARDINESS = 200;
private int countRun = 0;
private int countCalled = 0;
private int maxCalled = 10;
@Override
public void run() {
countCalled++;
if (countCalled < maxCalled) {
if (countCalled % 3 == 0) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
System.out.println("Push a new event to EDT");
frame1.getContentPane().setBackground(Color.red);
isThereReallyEDT();
}
});
} else {
if (this.getExecutionTime() < ALLOWED_TARDINESS) {
countRun++;
isThereReallyEDT(); // non on EDT
}
}
} else {
System.out.println("Terminating this madness");
System.exit(0);
}
}
};
periodicMonitor = scheduler.scheduleAtFixedRate(periodic, 0, taskPeriod, TimeUnit.SECONDS);
periodic.setThreadMonitor(periodicMonitor);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
isThereReallyEDT();
frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame1.getContentPane().add(new JLabel("Hello in frame 1"));
frame1.pack();
frame1.setLocation(100, 100);
frame1.setVisible(true);
}
});
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
Logger.getLogger(IsThereEDT.class.getName()).log(Level.SEVERE, null, ex);
}
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame2 = new JFrame("Frame 2");
frame2.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame2.getContentPane().add(new JLabel("Hello in frame 2"));
frame2.pack();
frame2.setLocation(200, 200);
frame2.setVisible(true);
isThereReallyEDT();
}
});
}
private void isThereReallyEDT() {
dateRun = new java.util.Date();
System.out.println(" Time at : " + sdf.format(dateRun));
if (EventQueue.isDispatchThread()) {
System.out.println("EventQueue.isDispatchThread");
} else {
System.out.println("There isn't Live EventQueue.isDispatchThread, why any reason for that ");
}
if (SwingUtilities.isEventDispatchThread()) {
System.out.println("SwingUtilities.isEventDispatchThread");
} else {
System.out.println("There isn't Live SwingUtilities.isEventDispatchThread, why any reason for that ");
}
System.out.println();
}
public static void main(String[] args) {
IsThereEDT isdt = new IsThereEDT();
}
}
abstract class AccurateScheduledRunnable implements Runnable {
private ScheduledFuture<?> thisThreadsMonitor;
public void setThreadMonitor(ScheduledFuture<?> monitor) {
this.thisThreadsMonitor = monitor;
}
protected long getExecutionTime() {
long delay = -1 * thisThreadsMonitor.getDelay(TimeUnit.MILLISECONDS);
return delay;
}
}