使用SwingWorker Java在线程池中等待任务

问题描述

我正在一个线程中模拟多个任务-当所有任务都应报告给GUI时。因此,我有一个独特的表单,其中包含4个面板,这些面板应答复并执行不同的任务..它们每个都应保持数据库合并并向GUI报告内容。在此示例中,我只是将数字写到textArea中。

public class FormMain extends JFrame {
    private JButton btnStart;
    private JPanel _panelTop,_panelMid,_panelBot;

    private PanelFoo panelFooA,panelFooB,panelFooC,panelFooD;

    private final List<String> ugsRj = Arrays.asList("AB");
    private final List<String> ugsMg = Arrays.asList("CD","EF");
    private final List<String> ugsBA = Arrays.asList("GH","IJ","KL");
    private final List<String> ugsPE = Arrays.asList("MN","OP","RS","TU");

    private void initialize() {
        this._panelTop = new JPanel();
        this._panelMid = new JPanel();
        this._panelBot = new JPanel();

        this.btnStart = new JButton("Start");
        this._panelBot.add(this.btnStart);

        this.panelFooA = new PanelFoo(this.ugsRj);
        this.panelFooB = new PanelFoo(this.ugsMg);
        this.panelFooC = new PanelFoo(this.ugsBA);
        this.panelFooD = new PanelFoo(this.ugsPE);
        _panelMid.setLayout(new BoxLayout(_panelMid,BoxLayout.X_AXIS));

        this._panelMid.add(this.panelFooA);
        this._panelMid.add(this.panelFooB);
        this._panelMid.add(this.panelFooC);
        this._panelMid.add(this.panelFooD);

    }

    public FormMain() {
        initialize();
        getContentPane().setLayout(new BorderLayout());
        setSize(800,516);
        setDefaultCloSEOperation(JFrame.EXIT_ON_CLOSE);
        getContentPane().add(this._panelTop,BorderLayout.norTH);
        getContentPane().add(this._panelMid,BorderLayout.CENTER);
        getContentPane().add(this._panelBot,BorderLayout.soUTH);

        this.btnStart.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(final ActionEvent e) {
                final AuthenticationUser auth = new AuthenticationUser();
                auth.setUser("test");
                auth.setPassword("p@ss");
//
                final SwingWorker<Void,Void> worker = new SwingWorker<Void,Void>() {
                    @Override
                    protected Void doInBackground() throws Exception {
                        final WorkerDoSomething w1 = new WorkerDoSomething(panelFooA);
                        w1.addPropertychangelistener(new ProgressListener(panelFooA.getProgressBar()));
                        final WorkerDoSomething w2 = new WorkerDoSomething(panelFooB);
                        w2.addPropertychangelistener(new ProgressListener(panelFooB.getProgressBar()));
                        final WorkerDoSomething w3 = new WorkerDoSomething(panelFooC);
                        w3.addPropertychangelistener(new ProgressListener(panelFooC.getProgressBar()));
                        final WorkerDoSomething w4 = new WorkerDoSomething(panelFooD);
                        w4.addPropertychangelistener(new ProgressListener(panelFooD.getProgressBar()));

                        w1.execute();
                        w2.execute();
                        w3.execute();
                        w4.execute();

                        return null;
                    }

                };
                worker.execute();
            }
        });

    }
}

public class ProgressListener implements Propertychangelistener {
    private JProgressBar bar;

    ProgressListener() {
    }

    ProgressListener(final JProgressBar b) {
        this.bar = b;
        this.bar.setValue(0);
    }

    @Override
    public void propertyChange(final PropertyChangeEvent evt) {
        // Determine whether the property is progress type
        if ("progress".equals(evt.getPropertyName())) {
            this.bar.setValue((int) evt.getNewValue());
        }
    }
}

public class PanelFoo extends JPanel {

    /**
     * 
     */
    private static final long serialVersionUID = -1400188281877395934L;
    private JLabel label;
    private JTextArea textArea;
    private JScrollPane scrollPanel;
    private JProgressBar progressBar;

    public PanelFoo(final List<String> listofStates) {
        setLayout(new FlowLayout());
        setSize(180,400);
        final ImageIcon icon = createImageIcon("/images/waiting-list.png","waiting start");
        this.label = new JLabel(listofStates.get(0),icon,SwingConstants.HORIZONTAL);
        add(this.label);

        this.textArea = new JTextArea("Numbers: \n");
        this.textArea.setWrapStyleWord(true);
        this.scrollPanel = new JScrollPane(this.textArea);
        this.scrollPanel.setPreferredSize(new Dimension(150,350));

        this.progressBar = new JProgressBar(0,100);

        add(this.scrollPanel);
        add(this.progressBar);

        setVisible(true);
    }

    /** Returns an ImageIcon,or null if the path was invalid. */
    public ImageIcon createImageIcon(final String path,final String description) {
        if (path != null) {
            ImageIcon imageIcon = new ImageIcon(getClass().getResource(path));
            final Image image = imageIcon.getimage(); 
            final Image newimg = image.getScaledInstance(30,30,Image.SCALE_SMOOTH);
            imageIcon = new ImageIcon(newimg,description);
            return imageIcon;

        } else {
            System.err.println("Couldn't find file: " + path);
            return null;
        }
    }

    public final JLabel getLabel() {
        return this.label;
    }

    public final void setLabel(final JLabel label) {
        this.label = label;
    }

    public final JTextArea getTextArea() {
        return this.textArea;
    }

    public final void setTextArea(final JTextArea textArea) {
        this.textArea = textArea;
    }

    public final JProgressBar getProgressBar() {
        return this.progressBar;
    }

    public final void setProgressBar(final JProgressBar progressBar) {
        this.progressBar = progressBar;
    }

}

public class WorkerDoSomething extends SwingWorker<Void,Void> {

    private JTextArea txtArea;
    private JLabel label;
    private Random r = new Random();

    WorkerDoSomething() {
    }

    public WorkerDoSomething(final PanelFoo panelFooInstance) {
        this.txtArea = panelFooInstance.getTextArea();
        this.label = panelFooInstance.getLabel();
    }

    private Integer randomInt(final int min,final int max) {
        final Integer randomNumber = this.r.nextInt((max - min) + 1) + min;

        return randomNumber;
    }

    @Override
    protected Void doInBackground() throws Exception {
        final Integer randomNumber = randomInt(10000000,1000000000);
        long j;
        int progress = 0;
        final int onePerCent = randomNumber / 100;
        final int onePerMillion = onePerCent / 10;
        for (j = 0; j <= randomNumber; j++) {
            if (j % onePerCent == 0) {
                progress = (int) j / onePerCent;
                setProgress(progress);
            }
            if (j % onePerMillion == 0) {
                publish(j);
            }
            //Thread.sleep(randomInt(1000,5000));
        }
        

        return null;
    }

    private void publish(final long num) {
        this.txtArea.append(num + "\n");
        this.txtArea.setCaretPosition(this.txtArea.getDocument().getLength());
    }

}

这毕竟是主要的GUI:

Main Gui

这是执行:

Running without sleep

我只需要在每个WorkerDoSomething的任务上等待一段时间,然后添加该行(以前已注释掉):Thread.sleep(randomInt(1000,5000));

但是,当我这样做时,..当然,整个执行都冻结了,..因为我使用单个线程来运行所有任务。

Running with sleep

解决方案吗?

哦...我必须在业务中使用java 1.8:

java version "1.8.0_251"
Java(TM) SE Runtime Environment (build 1.8.0_251-b08)
Java HotSpot(TM) 64-Bit Server VM (build 25.251-b08,mixed mode)

整个项目都在我个人的git

---首先使用调试透视图进行编辑

debug

解决方法

由于Swing使用10个线程的线程池运行工作程序,因此执行不会冻结。
如果您对此部分进行注释,则可以看到它正常工作:

mov eax,10
push eax
push 20
mov ecx,eax
pop eax

PS-为什么要在actionPerformed方法中创建一个新的SwingWorker?
为什么不这样简单地写:

@IBOutlet weak var Label: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        Label.font = LobsterTwo.bold.font(size: 50)
    }


}

public enum LobsterTwo: String {
    case bold = "LobsterTwo-Bold"
    case boldItalic = "LobsterTwo-BoldItalic"
    case italic = "LobsterTwo-Italic"
    
    public func font(size: CGFloat) -> UIFont {
        return UIFont(name: self.rawValue,size: size)!
    }
,

您是否读过SwingWorker类的 javadoc ?这是摘录:

SwingWorker类
类型参数:
T-此SwingWorker的doInBackground和get方法返回的结果类型
V-此SwingWorker的发布和处理方法用于执行中间结果的类型

您在publish()方法中正确调用了方法doInBackground(),但是尚未覆盖方法process()。请参阅Tasks that Have Interim Results。假设您的publish()方法确实应该是process()方法,那么这应该是类WorkerDoSomething

的声明
public class WorkerDoSomething extends SwingWorker<Void,Long> {

这应该是方法process()(而不是方法publish()

protected void process(List<Long> nums) {
    this.txtArea.append(nums.get(nums.size() - 1) + "\n");
    this.txtArea.setCaretPosition(this.txtArea.getDocument().getLength());
}

但是这样做不能解决您的问题。我无法解释为什么,但是如果您在方法Thread.sleep()中将调用的位置更改为doInBackground(),则可以解决问题。如果我将对方法sleep()的调用放在对setProgress()的调用之前,则GUI不会“冻结”。我想到了从this网页(名为 Java Swing如何-将冗长的任务放入SwingWorker

)中将睡眠的位置转移到睡眠的想法

这是我对您的应用程序的重写。我可以自由地重写其中的一部分,但实际上,您只需要注意WorkerDoSomething类即可。

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.List;
import java.util.Random;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingWorker;
import javax.swing.WindowConstants;

public class FormMain implements Runnable,ActionListener {
    private static final int  PANELS = 4;
    private static final String  START = "Start";

    private JFrame  frame;
    private PanelFoo[]  fooPanels;

    public FormMain() {
        fooPanels = new PanelFoo[PANELS];
        for (int i = 0; i < PANELS; i++) {
            fooPanels[i] = new PanelFoo();
        }
    }

    @Override // java.awt.event.ActionListener
    public void actionPerformed(ActionEvent event) {
        String actionCommand = event.getActionCommand();
        switch (actionCommand) {
            case START:
                start();
                break;
            default:
                JOptionPane.showMessageDialog(frame,actionCommand,"Unhandled",JOptionPane.WARNING_MESSAGE);
        }
    }

    @Override // java.lang.Runnable
    public void run() {
        createGui();
    }

    private JButton createButton(String text,int mnemonic,String tooltip) {
        JButton button = new JButton(text);
        button.setMnemonic(mnemonic);
        button.setToolTipText(tooltip);
        button.addActionListener(this);
        return button;
    }

    private JPanel createButtonsPanel() {
        JPanel buttonsPanel = new JPanel();
        buttonsPanel.add(createButton(START,KeyEvent.VK_S,"Start your engines!"));
        return buttonsPanel;
    }

    private void createGui() {
        frame = new JFrame();
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frame.add(createMainPanel(),BorderLayout.CENTER);
        frame.add(createButtonsPanel(),BorderLayout.PAGE_END);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    private JPanel createMainPanel() {
        JPanel mainPanel = new JPanel(new GridLayout(0,4,10,10));
        for (PanelFoo pf : fooPanels) {
            mainPanel.add(pf);
        }
        return mainPanel;
    }

    private void start() {
        for (PanelFoo pf : fooPanels) {
            pf.start();
        }
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new FormMain());
    }
}

class PanelFoo extends JPanel implements PropertyChangeListener {
    private static final long serialVersionUID = 4029040375048696554L;

    private JProgressBar  progressBar;
    private JTextArea  textArea;

    public PanelFoo() {
        super(new BorderLayout());
        textArea = new JTextArea(20,10);
        JScrollPane scrollPane = new JScrollPane(textArea);
        add(scrollPane,BorderLayout.CENTER);
        progressBar = new JProgressBar(0,100);
        add(progressBar,BorderLayout.PAGE_END);
    }

    public void appendText(String text) {
        textArea.append(text);
        textArea.append("\n");
    }

    @Override // java.beans.PropertyChangeListener
    public void propertyChange(PropertyChangeEvent evt) {
        if ("progress".equals(evt.getPropertyName())) {
            int progress = (Integer) evt.getNewValue();
            progressBar.setValue(progress);            
        }
    }

    public void start() {
        WorkerDoSomething worker = new WorkerDoSomething(this);
        worker.addPropertyChangeListener(this);
        worker.execute();
    }
}

class WorkerDoSomething extends SwingWorker<Void,Long> {
    private PanelFoo  fooPanel;
    private Random r = new Random();

    public WorkerDoSomething(PanelFoo pf) {
        fooPanel = pf;
    }

    @Override
    protected Void doInBackground() throws Exception {
        Integer randomNumber = randomInt(10000000,1000000000);
        long j;
        int progress = 0;
        final int onePerCent = randomNumber / 100;
        final int onePerMillion = onePerCent / 10;
        for (j = 0; j <= randomNumber; j++) {
            if (j % onePerCent == 0) {
                try {
                    Thread.sleep(1000);
                }
                catch (InterruptedException xInterrupted) {
                    // Ignore
                }
                progress = (int) j / onePerCent;
                setProgress(progress);
            }
            if (j % onePerMillion == 0) {
                publish(j);
            }
        }
        return null;
    }

    @Override
    protected void process(List<Long> numbers) {
        Long number = numbers.get(numbers.size() - 1);
        fooPanel.appendText(String.valueOf(number));
    }

    private Integer randomInt(final int min,final int max) {
        final Integer randomNumber = this.r.nextInt((max - min) + 1) + min;
        return randomNumber;
    }
}

从技术上讲,以上内容回答了您的问题,即:

有解决方案吗?

我相信我已经提供了一个解决方案,即使我无法解释它为什么起作用。