5

私はActionListenerEDTで呼び出されるこれを持っています。私のplot()関数は計算量が多く、簡単に5秒かかることがあります。GUIが期待どおりにハングしました。コードを追加しましたが、SwingUtilities.invokeLaterまだハングします。ヒーブ計算用に別のスレッドを生成しているので、GUIが応答するべきではありませんか?

final ActionListener applyListener = new ActionListener() 
        {
            @CommitingFunction
            public void actionPerformed(ActionEvent arg0) 
            {
                /*Don't do plotting in the EDT :)*/
                SwingUtilities.invokeLater(new Runnable() 
                {
                    public void run() 
                    {
                        plot();
                    }
                });
            }
        };
4

5 に答える 5

15

全くない。InvokeLaterは新しいスレッドを生成していません。invokeLaterは、Swingに明示的に「これにはイベントディスパッチスレッドを使用しますが、現在は使用しない」ように指示するために存在します。invokeおよびinvokeLaterは、他のスレッドからのイベントディスパッチスレッドに対してのみ安全な操作を実行できるようにするために存在します。これらのスレッドで実行するのではなく、EDTに実行するように指示します。

ActionListenerは非常に高速に実行され、RunnableonSwingのイベントディスパッチキューをスローします。次に、そこまで到達すると、plot()の実行に5秒かかります。

唯一の回避策は、plot()をリファクタリングすることです。SwingWorker(または同様のマルチスレッド戦略ですが、SwingWorkerがおそらくこれに最適です)を使用して、plot()のロジックを別のスレッドに実際に移動します。そのスレッドはSwingイベントディスパッチスレッドではないため、安全に何も描画できません。そのため、すべての描画操作は、invokeLater()を介して実行する必要があります。効率上の理由から、計算から保存された結果を使用して、1つのinvokeLater()ですべての描画操作を一度に実行するようにしてください。

于 2010-11-19T17:42:35.423 に答える
3

あなたは自分が思っていることとは逆のことをしています。EDTの外部で計算スレッドを実行する代わりに、EDTで明示的に呼び出しています。

SwingUtilities.invokeLater()は、EDTで、後で呼び出すためにランナブルをキューに入れます。代わりにSwingWorkerを使用します。

于 2010-11-19T17:43:26.217 に答える
1

invokeLaterは、GUIワークキューにタスクを追加します。他のすべてのタスクが実行された後に呼び出されますが、それでもGUIスレッドを使用します。

ExecutorServiceの使用を検討することをお勧めします。

@Adamが示唆しているように、実際の描画は、invokeLaterを介して行う必要があります。

于 2010-11-19T17:42:57.800 に答える
1

plot()関数の内容は表示しませんが、そこに絵を入れないでください。新しいスレッドで必要なものを計算し、EDTでペイントを行います。これを行うには、SwingWorkerを使用することをお勧めします

于 2010-11-19T17:43:04.070 に答える
1

これが私の会社のアプリに対して行ったことです。これは法的な理由による疑似コードですが、画面が応答しない場合はGUIが再起動します。SwingUtilitiesを使用してEDTを開始するときはいつでも、同じinitブロックで2つのウォッチャースレッドを作成します。1つのスレッドは、Swingユーティリティを使用してEDTスレッドに対してアクションを実行するだけです。別のスレッドが最初のスレッドを監視して、最初のスレッドが応答していると感じているかどうかを確認します。最初のスレッドは、非常に単純なコマンドを実行できる場合にのみ応答性を確認します。

通常の方法で実行している場合はisEDTCheckをtrueに設定し、デバッグモードではfalseに設定します(そうしないと、常に再起動されます。

    if (isEDTCheck) {
        new Thread("EDTHeartbeat") {
            @Override
            public void run() {
                Runnable thisThingYouDo = new Runnable() {
                    public void run() {
                        int x = 0;
                    }
                };
                while (true) {
                    // first thread says we are waiting, aka bad state
                    edtwait=true;
                    try {
                        javax.swing.SwingUtilities.invokeAndWait(thisThingYouDo);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    // first thread says we are not waiting, good state
                    edtwait=false;
                    try {
                        Thread.sleep(5000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        }.start();

        new Thread("EDTValidator") {
            @Override
            public void run() {
                while (true) {
                    // is first thread in bad state?
                    if (edtwait) {
                        try {
                            Thread.sleep(3000);
                            // after 3 seconds are we still in bad state?  if so, get rid of initial frame, pop up a dialog box in AWT that does no commands
                            if (edtwait) {
                                mainFrame.setVisible(false);
                                new Dialog();  
                            } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }


  public class Dialog extends Frame {
    private static final int WIDTH = 400;
    private static final int HEIGHT = 300;
    Frame f = null;
    public Dialog() {
        f = this;
        hasSomethingBeenEntered=false;
        this.setTitle("APP PROBLEM DETECTED");
        this.setSize(WIDTH, HEIGHT);
        this.setLocation((int)Toolkit.getDefaultToolkit().getScreenSize().getWidth() - myapp.width, 0);
        Panel p1 = new Panel() {
            @Override
            public void paint(final Graphics g) {
                int left = Dialog.WIDTH/2 - 45; // don't use WIDTH shadowed by Panel class
                int top = Dialog.HEIGHT/2 - 20; // same as above
                g.drawString("APP HAS DETECTED A PROBLEM", left, top);
            }
        };
        this.add("Center", p1);

        this.setAlwaysOnTop(true);
                 TextArea tb = new TextArea("APP HAS DETECTED A MAJOR PROBLEM\nIT WILL NOW RESTART IN 5 SECONDS");
        this.add(tb);
        this.setVisible(true);
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        restartApp();

    }

    private void restartApp() {
            Runtime.getRuntime().exec("cmd /c start cmd.exe /K \"cd C:\\Progra~1\\Common~1 && C:\\Progra~1\\Common~1\\MyAppDir\\myjavaapp.jar\"");
            System.exit(0);
       }
于 2012-08-02T19:49:21.197 に答える