Java SwingWorker线程同步

Java SwingWorker线程同步,java,multithreading,swing,synchronization,swingworker,Java,Multithreading,Swing,Synchronization,Swingworker,我创建了一个GUI应用程序,其中有4个独立的SwingWorker线程正在执行。它们的进度由单个进度条和旁边的数字(动态更新)指示。底部还有一个“总计”标签,它应该是所有4个线程进度的总和。但是,由于比赛条件的原因,总数计算不正确。到目前为止,我已经尝试使用syncrhonized关键字,并使用SwingWorker的publish()和process()方法。什么都没用。还有一个暂停和恢复按钮可以工作,但在“总人数”上造成了更大的差距 以下是我的对话框代码: public class Thre

我创建了一个GUI应用程序,其中有4个独立的SwingWorker线程正在执行。它们的进度由单个进度条和旁边的数字(动态更新)指示。底部还有一个“总计”标签,它应该是所有4个线程进度的总和。但是,由于比赛条件的原因,总数计算不正确。到目前为止,我已经尝试使用
syncrhonized
关键字,并使用SwingWorker的
publish()
process()
方法。什么都没用。还有一个暂停和恢复按钮可以工作,但在“总人数”上造成了更大的差距

以下是我的对话框代码:

public class ThreadTestDialog extends JDialog {
    private JPanel contentPane;
    private JButton buttonStart;
    private JButton buttonPause;
    private JProgressBar progressBar1;
    private JProgressBar progressBar2;
    private JProgressBar progressBar3;
    private JProgressBar progressBar4;
    private JButton buttonResume;
    private JLabel labelThread1;
    private JLabel labelThread2;
    private JLabel labelThread3;
    private JLabel labelThread4;
    private JLabel labelThread1Total;
    private JLabel labelThread2Total;
    private JLabel labelThread3Total;
    private JLabel labelThread4Total;
    private JLabel labelGrandTotal;
    private JLabel labelGrandTotalValue;

    public AppThread thread1 = new AppThread(labelThread1Total, progressBar1, 30, labelGrandTotalValue);
    public AppThread thread2 = new AppThread(labelThread2Total, progressBar2, 75, labelGrandTotalValue);
    public AppThread thread3 = new AppThread(labelThread3Total, progressBar3, 50, labelGrandTotalValue);
    public AppThread thread4 = new AppThread(labelThread4Total, progressBar4, 20, labelGrandTotalValue);

    public ThreadTestDialog() {
        setContentPane(contentPane);
        setModal(true);
        getRootPane().setDefaultButton(buttonStart);

        buttonStart.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                onStart();
            }
        });

        buttonPause.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                onPause();
            }
        });

        buttonResume.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                onResume();
            }
        });

        // call dispose() when cross is clicked
        setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                dispose();
            }
        });

        // call dispose() on ESCAPE
        contentPane.registerKeyboardAction(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                dispose();
            }
        }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
    }

    private void onStart() {
        thread1.execute();
        thread2.execute();
        thread3.execute();
        thread4.execute();
    }

    private void onPause() {
        thread1.setFlag(false);
        thread2.setFlag(false);
        thread3.setFlag(false);
        thread4.setFlag(false);
    }

    private void onResume() {
        int tempValue;

        tempValue = thread1.getValue();
        thread1 = new AppThread(tempValue, labelThread1Total, progressBar1, 30, labelGrandTotalValue);
        thread1.execute();

        tempValue = thread2.getValue();
        thread2 = new AppThread(tempValue, labelThread2Total, progressBar2, 75, labelGrandTotalValue);
        thread2.execute();

        tempValue = thread3.getValue();
        thread3 = new AppThread(tempValue, labelThread3Total, progressBar3, 50, labelGrandTotalValue);
        thread3.execute();

        tempValue = thread4.getValue();
        thread4 = new AppThread(tempValue, labelThread4Total, progressBar4, 20, labelGrandTotalValue);
        thread4.execute();

    }

    public static void main(String[] args) {
        ThreadTestDialog dialog = new ThreadTestDialog();
        dialog.pack();
        dialog.setVisible(true);
        System.exit(0);
    }
}
这是我的SwingWorker自定义类:

import javax.swing.*;
import java.util.List;

public class AppThread extends SwingWorker<Void, Integer> {
    private int value=0;
    private int sleepTime;
    private JLabel label;
    private JProgressBar progressBar;
    private JLabel grandTotal;
    private boolean flag=true;

    public AppThread (JLabel label, JProgressBar progressBar, int sleepTime, JLabel grandTotal) {
        this.sleepTime = sleepTime;
        this.label = label;
        this.progressBar = progressBar;
        this.grandTotal = grandTotal;
    }

    public AppThread (int value, JLabel label, JProgressBar progressBar, int sleepTime, JLabel grandTotal) {
        this.value = value;
        this.sleepTime = sleepTime;
        this.label = label;
        this.progressBar = progressBar;
        this.grandTotal = grandTotal;
    }

    public Void doInBackground() {
        for (int i = value; i <= 100; i++) {
            if (!flag) break;
            this.value = i;
            try {
                Thread.sleep(sleepTime);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            label.setText(Integer.toString(value));
            progressBar.setValue(value);
            progressBar.setStringPainted(true);

            grandTotal.setText(Integer.toString(Integer.parseInt(grandTotal.getText()) + 1));
        }
        return null;
    }

    public void done() {
    }

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

    public int getValue() {
        return value;
    }

    }
}
import javax.swing.*;
导入java.util.List;
公共类AppThread扩展SwingWorker{
私有int值=0;
私人睡眠时间;
私人标签;
私人JProgressBar progressBar;
私人JLabel grandTotal;
私有布尔标志=true;
公共AppThread(JLabel标签、JProgressBar progressBar、int sleepTime、JLabel grandTotal){
this.sleepTime=睡眠时间;
this.label=标签;
this.progressBar=progressBar;
this.grandTotal=grandTotal;
}
公共AppThread(int值、JLabel标签、JProgressBar progressBar、int休眠时间、JLabel grandTotal){
这个值=值;
this.sleepTime=睡眠时间;
this.label=标签;
this.progressBar=progressBar;
this.grandTotal=grandTotal;
}
公共无效doInBackground(){

对于(int i=value;i您违反了Swing的线程规则,从事件调度线程的上下文之外更新UI,而
SwingWorker
应该可以帮助您

避免将UI对象的引用传递给
SwingWorker
,而是使用其
过程
方法更新某些状态模型,或者使用其
属性更改侦听器
支持间接更新UI

下面是一个简单的示例,它使用
PropertyChangeListener
支持来更新进度条

注意,我已将
AppThread
与UI分离,因此UI现在承担更新UI的责任。该示例还可以动态扩展,因此您可以通过简单地更新创建它们的
for循环来增加
AppThread
的数量

ThreadTestDialog

您违反了
SwingWorker
的基本概念,但从
doInBackground
方法内部更新UI。相反,您应该使用
PropertyChangeListener
支持或
process
方法从我已经使用过的
process
更新UI,但将尝试使用
PropertyChange监听器
。谢谢
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JProgressBar;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class ThreadTestDialog extends JDialog {

    private JButton buttonStart;
    private Map<AppThread, JProgressBar> progressBars = new HashMap<>(4);
    private JProgressBar pbGrandTotal;

    public ThreadTestDialog() {
        setModal(true);
        getRootPane().setDefaultButton(buttonStart);

        buttonStart = new JButton("Start");
        buttonStart.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                onStart();
            }
        });

        // call dispose() when cross is clicked
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);

        setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridwidth = GridBagConstraints.REMAINDER;

        Random rnd = new Random();
        for (int index = 0; index < 4; index++) {
            AppThread appThread = new AppThread(rnd.nextInt(1000));
            appThread.addPropertyChangeListener(new PropertyChangeListener() {
                @Override
                public void propertyChange(PropertyChangeEvent evt) {
                    AppThread worker = (AppThread)evt.getSource();
                    String name = evt.getPropertyName();
                    if (name.equals("progress")) {
                        JProgressBar pb = progressBars.get(worker);
                        pb.setValue(worker.getProgress());

                    } else if (name.equals("done")) {
                        // Now you can do something when the worker completes...
                    }
                    updateTotalProgress();
                }
            });
            JProgressBar pb = new JProgressBar(0, 100);

            progressBars.put(appThread, pb);
            add(pb, gbc);
        }

        pbGrandTotal = new JProgressBar(0, progressBars.size() * 100);
        add(pbGrandTotal, gbc);

        add(buttonStart, gbc);
    }

    protected void updateTotalProgress() {
        int totalProgress = 0;
        for (Map.Entry<AppThread, JProgressBar> entry : progressBars.entrySet()) {
            totalProgress += entry.getKey().getProgress();
        }
        pbGrandTotal.setValue(totalProgress);
    }

    private void onStart() {
        for (Map.Entry<AppThread, JProgressBar> entry : progressBars.entrySet()) {
            entry.getKey().execute();
        }
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }
                ThreadTestDialog dialog = new ThreadTestDialog();
                dialog.pack();
                dialog.setVisible(true);
            }
        });
    }
}
import javax.swing.SwingWorker;

public class AppThread extends SwingWorker<Void, Integer> {

    private int value = 0;
    private int sleepTime;

    public AppThread(int sleepTime) {
        this.sleepTime = sleepTime;
    }

    public Void doInBackground() {
        for (int i = value; i <= 100; i++) {
            this.value = i;
            try {
                Thread.sleep(sleepTime);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            setProgress(value);
        }
        return null;
    }

}