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