在javax.swing.SwingUtilities.invokeLater调用的createAndShowGUI()方法中,如下所示......:
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
...我有以下代码,它使用invokeLater启动多个线程,其中每个线程在运行时增加progBar的值:
int times = 20;
for(int x = 0; x < times; x = x+1) {
new Thread("T") {
public void run() {
try {
Thread.sleep(5000);
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
progBar.setValue(progBar.getValue()+1);
}
});
}
}.start();
}
我如何知道所有线程的完成位置?如果我在invokeLater中使用计数器,我想我会遇到竞争条件。那么正确的方法是什么?我应该使用互斥锁吗? Swing是否为此提供了一些设施?感谢。
我已根据http://www.java2s.com/Code/Java/Threads/InvokeExampleSwingandthread.htm
以这种方式实现了代码答案 0 :(得分:2)
传递给Runnable
的{{1}}都在单个事件调度线程上执行。由于它们都是由不同的线程发送的,因此没有特定的顺序,但它们是一个接一个地执行的。
因此,一旦您通过将UI更新移动到传递给invokeLater
的{{1}}来修复代码,您就可以使用Swings通知机制来了解作业的完成情况:
Runnable
答案 1 :(得分:1)
InvokeLater
实际上运行了从Swing EventDispatchThread
调用的所有东西 - 这可能根本不是你想要的。它们不会同时运行,它们会一个接一个地运行。更糟糕的是,在您的示例中,您正在从线程中更改Swing控件,但之后使用InvokeLater
。
这意味着计数器实际上是线程安全的。
您可能需要使用'SwingWorker'或'ExecutorService'并将结果发回EDT进行显示。
答案 2 :(得分:-2)
我如何知道所有线程的完成位置?如果我使用计数器 在invokeLater内部我想我会遇到竞争条件..
break;
那么正确的做法是什么?
JProgressBar在API中的范围从0到100,只是为了测试循环中的值是100还是更大,然后使用break;
使用Runnable #Thread而不是普通的vanilla线程
例如(相同的输出应该来自SwingWorker,但是有超过12个实例,AFAIK注意有一个关于重载数量的错误...,但是为了目的,因为论坛的代码可以创建similair代码使用SwingWorker)
import java.awt.Component;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
public class TableWithProgressBars {
private static final int maximum = 100;
private JFrame frame = new JFrame("Progressing");
Integer[] oneRow = {0, 0, 0, 0};
private String[] headers = {"One", "Two", "Three", "Four"};
private Integer[][] data = {oneRow, oneRow, oneRow, oneRow, oneRow,};
private DefaultTableModel model = new DefaultTableModel(data, headers);
private JTable table = new JTable(model);
public TableWithProgressBars() {
table.setDefaultRenderer(Object.class, new ProgressRenderer(0, maximum));
table.setPreferredScrollableViewportSize(table.getPreferredSize());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JScrollPane(table));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
new Thread(new Runnable() {
@Override
public void run() {
Object waiter = new Object();
synchronized (waiter) {
int rows = model.getRowCount();
int columns = model.getColumnCount();
Random random = new Random(System.currentTimeMillis());
boolean done = false;
while (!done) {
int row = random.nextInt(rows);
int column = random.nextInt(columns);
Integer value = (Integer) model.getValueAt(row, column);
value++;
if (value <= maximum) {
model.setValueAt(value, row, column);
// model.setValueAt(... must be wrapped into invokeLater()
// for production code, otherwise nothing will be repainted
// interesting bug or feature in Java7 051, looks like as
// returns some EDT features from Java6 back to Java7 ???
try {
waiter.wait(15);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
done = true;
for (row = 0; row < rows; row++) {
for (column = 0; column < columns; column++) {
if (!model.getValueAt(row, column).equals(maximum)) {
done = false;
break;
}
}
if (!done) {
break;
}
}
}
frame.setTitle("All work done");
}
}
}).start();
}
private class ProgressRenderer extends JProgressBar implements TableCellRenderer {
private static final long serialVersionUID = 1L;
public ProgressRenderer(int min, int max) {
super(min, max);
this.setStringPainted(true);
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
this.setValue((Integer) value);
return this;
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new TableWithProgressBars();
}
});
}
}