Java SwingWorker未在任务完成时终止

Java SwingWorker未在任务完成时终止,java,multithreading,swing,progress-bar,swingworker,Java,Multithreading,Swing,Progress Bar,Swingworker,好的,我已经和SwingWorker玩了一会儿,得到了一些用于更新gui的简化代码,但是我很难弄清楚如何让线程在完成时正确终止。目前,它仅通过停止选项终止。我如何设置它,使它在完成进程时也能正确终止线程?当前,后返回null它转到包行并挂起 我的代码如下: package concurrency; import java.util.List; import java.util.Random; import java.awt.event.ActionListener; import ja

好的,我已经和SwingWorker玩了一会儿,得到了一些用于更新gui的简化代码,但是我很难弄清楚如何让线程在完成时正确终止。目前,它仅通过停止选项终止。我如何设置它,使它在完成进程时也能正确终止线程?当前,
后返回null它转到包行并挂起

我的代码如下:

    package concurrency;

import java.util.List;
import java.util.Random;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.awt.Insets;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;

public class PBTest extends JFrame implements ActionListener {
    private final GridBagConstraints constraints;
    private final JProgressBar pb, pbF;
    private final JButton theButton;
    private PBTask pbTask;

    private JProgressBar makePB() {
        JProgressBar p = new JProgressBar(0,100);
        p.setValue(0);
        p.setStringPainted(true);
        getContentPane().add(p, constraints);
        return p;       
    }

    public PBTest() {
        super("PBTest");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Make text boxes
        getContentPane().setLayout(new GridBagLayout());
        constraints = new GridBagConstraints();
        constraints.insets = new Insets(3, 10, 3, 10);

        pb = makePB();
        pbF = makePB();

        //Make buttons
        theButton = new JButton("Start");
        theButton.setActionCommand("Start");
        theButton.addActionListener(this);
        getContentPane().add(theButton, constraints);

        //Display the window.
        pack();
        setVisible(true);
    }

    private static class UpdatePB {
        private final int pb1, pb2;
        UpdatePB(int pb1s, int pb2s) {
            this.pb1 = pb1s;
            this.pb2 = pb2s;
        }
    }

    private class PBTask extends SwingWorker<Void, UpdatePB> {
        @Override
        protected Void doInBackground() {
            int prog1 = 0;
            int prog2 = 0;
            Random random = new Random();

            while (prog2 < 100) {
                if(prog1 >= 100) {
                    prog1 = 0;
                }
                //Sleep for up to one second.
                try {
                    Thread.sleep(random.nextInt(1000));
                } catch (InterruptedException ignore) {}
                //Make random progress.
                prog1 += random.nextInt(10);
                prog2 += random.nextInt(5);
                publish(new UpdatePB(prog1, prog2));
            }
            return null;
        }

        @Override
        protected void process(List<UpdatePB> pairs) {
            UpdatePB pair = pairs.get(pairs.size() - 1);
                pb.setValue(pair.pb1);
                pbF.setValue(pair.pb2);
        }
    }

    public void actionPerformed(ActionEvent e) {
        if ("Start" == e.getActionCommand() && pbTask == null) {
            theButton.setText("Stop");
            theButton.setActionCommand("Stop");
            (pbTask = new PBTask()).execute();
        } else if ("Stop" == e.getActionCommand()) {
            theButton.setText("Start");
            theButton.setActionCommand("Start");
            pbTask.cancel(true);
            pbTask = null;
        } else {
            alertMsg("Thread still running.");
        }

    }

    static void alertMsg(String theAlert) {
        JOptionPane.showMessageDialog(null, theAlert);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new PBTest();
            }
        });
    }
}
包并发;
导入java.util.List;
导入java.util.Random;
导入java.awt.event.ActionListener;
导入java.awt.event.ActionEvent;
导入java.awt.GridBagLayout;
导入java.awt.GridBagConstraints;
导入java.awt.Insets;
导入javax.swing.JButton;
导入javax.swing.JFrame;
导入javax.swing.JOptionPane;
导入javax.swing.JProgressBar;
导入javax.swing.SwingUtilities;
导入javax.swing.SwingWorker;
公共类PBTest扩展JFrame实现ActionListener{
私有最终网格约束;
私人最终JProgressBar pb,pbF;
私人最终按钮按钮;
专用PBTask-PBTask;
私有JProgressBar makePB(){
JProgressBar p=新的JProgressBar(0100);
p、 设定值(0);
p、 设置字符串已绘制(真);
getContentPane()。添加(p,约束);
返回p;
}
公共测试(){
超级(“PBTest”);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//创建文本框
getContentPane().setLayout(新的GridBagLayout());
约束=新的GridBagConstraints();
constraints.insets=新的insets(3,10,3,10);
pb=makePB();
pbF=makePB();
//做钮扣
按钮=新按钮(“开始”);
setActionCommand(“开始”);
addActionListener按钮(此按钮);
getContentPane().add(按钮,约束);
//显示窗口。
包装();
setVisible(真);
}
私有静态类UpdatePB{
私人最终int pb1、pb2;
UpdatePB(intPB1s,intPB2s){
这1.pb1=pb1s;
这是pb2=pb2s;
}
}
私有类PBTask扩展SwingWorker{
@凌驾
受保护的Void doInBackground(){
int prog1=0;
int prog2=0;
随机=新随机();
而(prog2<100){
如果(prog1>=100){
prog1=0;
}
//最多睡一秒钟。
试一试{
Thread.sleep(random.nextInt(1000));
}捕获(中断异常忽略){}
//随机取得进展。
prog1+=random.nextInt(10);
prog2+=random.nextInt(5);
发布(新的UpdatePB(prog1,prog2));
}
返回null;
}
@凌驾
受保护的无效进程(列表对){
UpdatePB pair=pairs.get(pairs.size()-1);
pb.设定值(对pb1);
设置值(对pb2);
}
}
已执行的公共无效操作(操作事件e){
如果(“开始”==e.getActionCommand()&&pbTask==null){
按钮。设置文本(“停止”);
按钮。设置操作命令(“停止”);
(pbTask=new pbTask()).execute();
}否则,如果(“停止”==e.getActionCommand()){
按钮。设置文本(“开始”);
setActionCommand(“开始”);
pbTask.cancel(true);
pbTask=null;
}否则{
alertMsg(“线程仍在运行”);
}
}
静态void alertMsg(字符串theAlert){
showMessageDialog(null,theAlert);
}
公共静态void main(字符串[]args){
SwingUtilities.invokeLater(新的Runnable(){
公开募捐{
新的PBTest();
}
});
}
}
注意:这基本上是对Java教程的“flipper”示例的修改。。。目前,我与其说是一名程序员,不如说是一名代码黑客(/sad face/,lol),所以我有点不知所措,不知下一步该去哪里

无论如何,代码在完成之前都会按预期工作。我尝试添加
done()
方法,但它从未尝试运行它,它总是转到包行(在逐步执行调试器时)并挂起。我应该返回一个值而不是null或其他什么吗


提前感谢您的帮助

我不确定你想达到什么目的。 你的例子很好。辅助线程一直运行到结束。 如果您想等到它结束后再做一些事情,您必须在代码中的某个地方调用方法pbTask.get()。否则,它将在不影响任何UI组件的情况下安静地完成

考虑对您的方法进行以下更改,以查看它现在的行为。注意,UI冻结是因为您让UI等待线程完成,但只有当WorkerThread完成时,输出“DONE”才会出现在日志中

public void actionPerformed(ActionEvent e) {
    if ("Start" == e.getActionCommand() && pbTask == null) {
        theButton.setText("Stop");
        theButton.setActionCommand("Stop");
        (pbTask = new PBTask()).execute();
    } else if ("Stop" == e.getActionCommand()) {
        theButton.setText("Start");
        theButton.setActionCommand("Start");
        pbTask.cancel(true);
        pbTask = null;
    } else {
        alertMsg("Thread still running.");
    }
    try {
        pbTask.get();
    } catch (InterruptedException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    } catch (ExecutionException e1) {
        // TODO Auto-generated catch block
        e1.printStackTrace();
    }
    System.out.println("DONE");
}
这一变化只是为了说明差异。为了编写实际的代码,我们需要更多地了解您试图实现的目标


若我的超感官能力还可以,那个么你们可能想把按钮扳回“开始”。为此,您需要在Worker中重写done()方法:

private class PBTask extends SwingWorker<Void, UpdatePB> {
    @Override
    protected Void doInBackground() {
        int prog1 = 0;
        int prog2 = 0;
        Random random = new Random();

        while (prog2 < 100) {
            if(prog1 >= 100) {
                prog1 = 0;
            }
            //Sleep for up to one second.
            try {
                Thread.sleep(random.nextInt(100));
            } catch (InterruptedException ignore) {}
            //Make random progress.
            prog1 += random.nextInt(10);
            prog2 += random.nextInt(5);
            publish(new UpdatePB(prog1, prog2));
        }
        return null;
    }

    @Override
    protected void process(List<UpdatePB> pairs) {
        UpdatePB pair = pairs.get(pairs.size() - 1);
            pb.setValue(pair.pb1);
            pbF.setValue(pair.pb2);
    }

    @Override
    protected void done() {
        super.done();
        theButton.setText("Start");
        theButton.setActionCommand("Start");
    }
}
私有类PBTask扩展SwingWorker{
@凌驾
受保护的Void doInBackground(){
int prog1=0;
int prog2=0;
随机=新随机();
而(prog2<100){
如果(prog1>=100){
prog1=0;
}
//最多睡一秒钟。
试一试{
Thread.sleep(random.nextInt(100));
}捕获(中断异常忽略){}
//随机取得进展。
prog1+=random.nextInt(10);
prog2+=random.nextInt(5);
发布(新更新)EPB(pr
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;

public class SwingWorkerExample extends JFrame implements ActionListener {

    private static final long serialVersionUID = 1L;
    private final JButton startButton, stopButton;
    private JScrollPane scrollPane = new JScrollPane();
    private JList listBox = null;
    private DefaultListModel listModel = new DefaultListModel();
    private final JProgressBar progressBar;
    private mySwingWorker swingWorker;

    public SwingWorkerExample() {
        super("SwingWorkerExample");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        getContentPane().setLayout(new GridLayout(2, 2));
        startButton = makeButton("Start");
        stopButton = makeButton("Stop");
        stopButton.setEnabled(false);
        progressBar = makeProgressBar(0, 99);
        listBox = new JList(listModel);
        scrollPane.setViewportView(listBox);
        getContentPane().add(scrollPane);
        //Display the window.
        pack();
        setVisible(true);
    }
//Class SwingWorker<T,V> T - the result type returned by this SwingWorker's doInBackground
//and get methods V - the type used for carrying out intermediate results by this SwingWorker's 
//publish and process methods

    private class mySwingWorker extends javax.swing.SwingWorker<ArrayList<Integer>, Integer> {
//The first template argument, in this case, ArrayList<Integer>, is what s returned by doInBackground(), 
//and by get(). The second template argument, in this case, Integer, is what is published with the 
//publish method. It is also the data type which is stored by the java.util.List that is the parameter
//for the process method, which recieves the information published by the publish method.

        @Override
        protected ArrayList<Integer> doInBackground() {
//Returns items of the type given as the first template argument to the SwingWorker class.
            if (javax.swing.SwingUtilities.isEventDispatchThread()) {
                System.out.println("javax.swing.SwingUtilities.isEventDispatchThread() returned true.");
            }
            Integer tmpValue = new Integer(1);
            ArrayList<Integer> list = new ArrayList<Integer>();
            for (int i = 0; i < 100; i++) {
                for (int j = 0; j < 100; j++) { //find every 100th prime, just to make it slower
                    tmpValue = FindNextPrime(tmpValue.intValue());
//isCancelled() returns true if the cancel() method is invoked on this class. That is the proper way
//to stop this thread. See the actionPerformed method.
                    if (isCancelled()) {
                        System.out.println("SwingWorker - isCancelled");
                        return list;
                    }
                }
//Successive calls to publish are coalesced into a java.util.List, which is what is received by process, 
//which in this case, isused to update the JProgressBar. Thus, the values passed to publish range from 
//1 to 100.
                publish(new Integer(i));
                list.add(tmpValue);
            }
            return list;
        }//Note, always use java.util.List here, or it will use the wrong list.

        @Override
        protected void process(java.util.List<Integer> progressList) {
//This method is processing a java.util.List of items given as successive arguments to the publish method.
//Note that these calls are coalesced into a java.util.List. This list holds items of the type given as the
//second template parameter type to SwingWorker. Note that the get method below has nothing to do with the 
//SwingWorker get method; it is the List's get method. This would be a good place to update a progress bar.
            if (!javax.swing.SwingUtilities.isEventDispatchThread()) {
                System.out.println("javax.swing.SwingUtilities.isEventDispatchThread() + returned false.");
            }
            Integer percentComplete = progressList.get(progressList.size() - 1);
            progressBar.setValue(percentComplete.intValue());
        }

        @Override
        protected void done() {
            System.out.println("doInBackground is complete");
            if (!javax.swing.SwingUtilities.isEventDispatchThread()) {
                System.out.println("javax.swing.SwingUtilities.isEventDispatchThread() + returned false.");
            }
            try {
//Here, the SwingWorker's get method returns an item of the same type as specified as the first type parameter
//given to the SwingWorker class.
                ArrayList<Integer> results = get();
                for (Integer i : results) {
                    listModel.addElement(i.toString());
                }
            } catch (Exception e) {
                System.out.println("Caught an exception: " + e);
            }
            startButton();
        }

        boolean IsPrime(int num) { //Checks whether a number is prime
            int i;
            for (i = 2; i <= num / 2; i++) {
                if (num % i == 0) {
                    return false;
                }
            }
            return true;
        }

        protected Integer FindNextPrime(int num) { //Returns next prime number from passed arg.       
            do {
                if (num % 2 == 0) {
                    num++;
                } else {
                    num += 2;
                }
            } while (!IsPrime(num));
            return new Integer(num);
        }
    }

    private JButton makeButton(String caption) {
        JButton b = new JButton(caption);
        b.setActionCommand(caption);
        b.addActionListener(this);
        getContentPane().add(b);
        return b;
    }

    private JProgressBar makeProgressBar(int min, int max) {
        JProgressBar progressBar1 = new JProgressBar();
        progressBar1.setMinimum(min);
        progressBar1.setMaximum(max);
        progressBar1.setStringPainted(true);
        progressBar1.setBorderPainted(true);
        getContentPane().add(progressBar1);
        return progressBar1;
    }

    private void startButton() {
        startButton.setEnabled(true);
        stopButton.setEnabled(false);
        System.out.println("SwingWorker - Done");
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if ("Start" == null ? e.getActionCommand() == null : "Start".equals(e.getActionCommand())) {
            startButton.setEnabled(false);
            stopButton.setEnabled(true);
// Note that it creates a new instance of the SwingWorker-derived class. Never reuse an old one.
            (swingWorker = new mySwingWorker()).execute(); // new instance
        } else if ("Stop" == null ? e.getActionCommand() == null : "Stop".equals(e.getActionCommand())) {
            startButton.setEnabled(true);
            stopButton.setEnabled(false);
            swingWorker.cancel(true); // causes isCancelled to return true in doInBackground
            swingWorker = null;
        }
    }

    public static void main(String[] args) {
// Notice that it kicks it off on the event-dispatching thread, not the main thread.
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                SwingWorkerExample swingWorkerExample = new SwingWorkerExample();
            }
        });
    }
}