21

done()のメソッドのJavadocSwingWorker:

doInBackgroundメソッドが終了した後、イベントディスパッチスレッドで実行されます。

キャンセルされた労働者の場合、それは真実ではないという手がかりがあります。
Doneはそれぞれの場合(通常の終了またはキャンセル)に呼び出されますが、通常の終了の場合と同様に、EDTにエンキューされていないcancelled場合に呼び出されます。

doneaSwingWorkerがキャンセルされた場合に、が呼び出されたときのより正確な分析はありますか?

明確化:この質問は、どのようにするかではありません。ここでは、が正しい方法でキャンセルされていると想定しています。 そして、それは、スレッドが終了することになっているときにまだ機能しているということではありません。cancelSwingWorkerSwingWorker

4

6 に答える 6

21

スレッドがキャンセルされたとき

myWorkerThread.cancel(true/false);

doneメソッドは(非常に驚くべきことに)cancelメソッド自体によって呼び出されます。

予想されることですが、実際には実行されません:
-cancelを呼び出します(mayInterruptを使用するかどうかに関係なく)-cancel
スレッドのキャンセルを設定します
-doInBackgroundが終了します-done
が呼び出されます*
(*doneはEDTにエンキューされますつまり、EDTがビジーの場合、EDTが実行を終了した後に発生します)

実際に何が起こるか:
-キャンセルを呼び出す(mayInterruptを使用するかどうかに関係なく)
-キャンセルスレッドキャンセルの設定
-完了はキャンセルコードの一部として呼び出されます*
-doInBackgroundは、ループが終了すると終了します
(*完了はEDTにエンキューされませんが、キャンセルコールに呼び出されるため、EDTに非常にすぐに影響します。これは、多くの場合GUIです)

これを証明する簡単な例を示します。
コピー、貼り付け、実行します。
1.done内でランタイム例外を生成します。スタックスレッドは、doneがcancelによって呼び出されることを示しています。
2.キャンセルから約4秒後に、doInBackgroundから挨拶が届きます。これは、スレッドが終了する前にdoneが呼び出されたことを激しく証明します。

import java.awt.EventQueue;
import javax.swing.SwingWorker;

public class SwingWorker05 {
public static void main(String [] args) {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            try {
            W w = new W();
            w.execute();
            Thread.sleep(1000);
            try{w.cancel(false);}catch (RuntimeException rte) {
                rte.printStackTrace();
            }
            Thread.sleep(6000);
            } catch (InterruptedException ignored_in_testing) {}
        }

    });
}

public static class W extends SwingWorker <Void, Void> {

    @Override
    protected Void doInBackground() throws Exception {
        while (!isCancelled()) {
            Thread.sleep(5000);
        }
        System.out.println("I'm still alive");
        return null;
    }

    @Override
    protected void done() {throw new RuntimeException("I want to produce a stack trace!");}

}

}
于 2011-06-01T16:32:54.963 に答える
6

done()いずれにせよ、ワーカーがキャンセルされたか、正常に終了したかに関係なく、が呼び出されます。それにもかかわらず、doInBackgroundがまだ実行中であり、doneメソッドがすでに呼び出されている場合があります(これはcancel()、スレッドがすでに終了しているかどうかに関係なく、内部で実行されます)。簡単な例はここにあります:

public static void main(String[] args) throws AWTException {
    SwingWorker<Void, Void> sw = new SwingWorker<Void, Void>() {

        protected Void doInBackground() throws Exception {
            System.out.println("start");
            Thread.sleep(2000);
            System.out.println("end");
            return null;
        }

        protected void done() {
            System.out.println("done " + isCancelled());
        }
    };
    sw.execute();
    try {
        Thread.sleep(1000);
        sw.cancel(false);
        Thread.sleep(10000);
    } catch (InterruptedException ex) {
        ex.printStackTrace();
    }

doneしたがって、終了する前に呼び出される場合がありdoInBackgroundます。

于 2011-06-01T16:34:45.427 に答える
1

something is possible, other could be illusion

really nice outPut

run:
***removed***
java.lang.RuntimeException: I want to produce a stack trace!
        at help.SwingWorker05$W.done(SwingWorker05.java:71)
        at javax.swing.SwingWorker$5.run(SwingWorker.java:717)
        at javax.swing.SwingWorker.doneEDT(SwingWorker.java:721)
        at javax.swing.SwingWorker.access$100(SwingWorker.java:207)
        at javax.swing.SwingWorker$2.done(SwingWorker.java:284)
        at java.util.concurrent.FutureTask$Sync.innerCancel(FutureTask.java:293)
        at java.util.concurrent.FutureTask.cancel(FutureTask.java:76)
        at javax.swing.SwingWorker.cancel(SwingWorker.java:526)
        at help.SwingWorker05$1.run(SwingWorker05.java:25)
        at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:597)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)
I'm still alive
Thread Status with Name :SwingWorker1, SwingWorker Status is STARTED
SwingWorker by tutorial's background process has completed
Thread Status with Name :SwingWorker1, SwingWorker Status is DONE
Thread Status with Name :look here what's possible with SwingWorker, SwingWorker Status is STARTED
BUILD SUCCESSFUL (total time: 10 seconds)

from

import java.awt.EventQueue;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.SwingWorker;

public class SwingWorker05 {

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            public void run() {
                try {
                    W w = new W();
                    w.addPropertyChangeListener(
                            new SwingWorkerCompletionWaiter("look here what's possible with SwingWorker"));
                    w.execute();
                    Thread.sleep(1000);
                    try {
                        w.cancel(false);
                    } catch (RuntimeException rte) {
                        rte.printStackTrace();
                    }
                    Thread.sleep(6000);
                } catch (InterruptedException ignored_in_testing) {
                }
            }
        });

        final MySwingWorker mySW = new MySwingWorker();
        mySW.addPropertyChangeListener(new SwingWorkerCompletionWaiter("SwingWorker1"));
        mySW.execute();
    }

    private static class MySwingWorker extends SwingWorker<Void, Void> {

        private static final long SLEEP_TIME = 250;

        @Override
        protected Void doInBackground() throws Exception {
            Thread.sleep(SLEEP_TIME);
            return null;
        }

        @Override
        protected void done() {
            System.out.println("SwingWorker by tutorial's background process has completed");
        }
    }

    public static class W extends SwingWorker {

        @Override
        protected Object doInBackground() throws Exception {
            while (!isCancelled()) {
                Thread.sleep(5000);
            }

            System.out.println("I'm still alive");
            return null;
        }

        @Override
        protected void done() {
            System.out.println("***remove***");
            throw new RuntimeException("I want to produce a stack trace!");
        }
    }

    private static class SwingWorkerCompletionWaiter implements PropertyChangeListener {

        private String str;

        SwingWorkerCompletionWaiter(String str) {
            this.str = str;
        }

        @Override
        public void propertyChange(PropertyChangeEvent event) {
            if ("state".equals(event.getPropertyName()) && SwingWorker.StateValue.DONE == event.getNewValue()) {
                System.out.println("Thread Status with Name :" + str + ", SwingWorker Status is " + event.getNewValue());
            } else if ("state".equals(event.getPropertyName()) && SwingWorker.StateValue.PENDING == event.getNewValue()) {
                System.out.println("Thread Status with Mame :" + str + ", SwingWorker Status is " + event.getNewValue());
            } else if ("state".equals(event.getPropertyName()) && SwingWorker.StateValue.STARTED == event.getNewValue()) {
                System.out.println("Thread Status with Name :" + str + ", SwingWorker Status is " + event.getNewValue());
            } else {
                System.out.println("Thread Status with Name :" + str + ", Something wrong happends ");
            }
        }
    }
}
于 2011-06-01T21:03:15.773 に答える
1

SwingWorkerが修正されるまでhttp://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6826514 ここでは、基本的な(類似の)関数を備えた単純な(テスト済みの)バージョン、次にSwingWorker

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package tools;

import java.util.LinkedList;
import java.util.List;
import javax.swing.SwingUtilities;

/**
 *
 * @author patrick
 */
public abstract class MySwingWorker<R,P> {

    protected abstract R doInBackground() throws Exception;
    protected abstract void done(R rvalue, Exception ex, boolean canceled);
    protected void process(List<P> chunks){}
    protected void progress(int progress){}

    private boolean cancelled=false;
    private boolean done=false;
    private boolean started=false;
    final private Object syncprogress=new Object();
    boolean progressstate=false;
    private int progress=0;
    final private Object syncprocess=new Object();
    boolean processstate=false;
    private LinkedList<P> chunkes= new LinkedList<>();

    private Thread t= new Thread(new Runnable() {
        @Override
        public void run() {
            Exception exception=null;
            R rvalue=null;
            try {
                rvalue=doInBackground();
            } catch (Exception ex) {
                exception=ex;
            }

            //Done:
            synchronized(MySwingWorker.this)
            {
                done=true;
                final Exception cexception=exception;
                final R crvalue=rvalue;
                final boolean ccancelled=cancelled;

                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        done(crvalue, cexception, ccancelled);
                    }
                });
            }

        }
    });    

    protected final void publish(P p)
    {
        if(!Thread.currentThread().equals(t))
            throw new UnsupportedOperationException("Must be called from worker Thread!");
        synchronized(syncprocess)
        {
            chunkes.add(p);
            if(!processstate)
            {
                processstate=true;
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        List<P> list;
                        synchronized(syncprocess)
                        {
                            MySwingWorker.this.processstate=false;
                            list=MySwingWorker.this.chunkes;
                            MySwingWorker.this.chunkes= new LinkedList<>();
                        }
                        process(list);
                    }
                });
            }
        }
    }

    protected final void setProgress(int progress)
    {
        if(!Thread.currentThread().equals(t))
            throw new UnsupportedOperationException("Must be called from worker Thread!");
        synchronized(syncprogress)
        {
            this.progress=progress;
            if(!progressstate)
            {
                progressstate=true;
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        int value;
                        //Acess Value
                        synchronized(syncprogress)
                        {
                            MySwingWorker.this.progressstate=false;
                            value=MySwingWorker.this.progress;
                        }
                        progress(value);
                    }
                });
            }
        }
    }

    public final synchronized void execute()
    {
        if(!started)
        {
            started=true;
            t.start();
        }
    }

    public final synchronized boolean isRunning()
    {
        return started && !done;
    }

    public final synchronized boolean isDone()
    {
        return done;
    }

    public final synchronized boolean isCancelled()
    {
        return cancelled;
    }

    public final synchronized void cancel()
    {
        if(started && !cancelled && !done)
        {
            cancelled=true;
            if(!Thread.currentThread().equals(t))
                t.interrupt();
        }
    }

}
于 2013-09-21T12:32:38.010 に答える
0

Javaドキュメントから:cancel(boolean mayInterruptIfRunning) "mayInterruptIfRunning-このタスクを実行しているスレッドを中断する必要がある場合はtrue。それ以外の場合は、進行中のタスクを完了できます。"

期待どおりに動作するように見えるcancel(false)の代わりにcancel(true)を呼び出すと。

EventQueue.isDispatchThread()を使用してEDTが呼び出されたdone()を見たことがありません

于 2012-11-25T12:34:15.030 に答える
0

return Voidを使用する場合:... @ Override public Void doInBackground(){.. ..

done()は、doInBackground()が終了したときに呼び出されます。

return Voidを使用しない場合:... @ Override public boolean doInBackground(){.. ..

done()は無視され、戻ってきたために終了したことがわかります。

于 2017-04-27T01:27:53.333 に答える