这个问题是关于 volatile 关键字的用法。我有一个 Swing 应用程序,它显示一个表格,并且有一个单独的线程向表格模型添加行。根据this看来我必须将某些字段标记为 volatile ,以确保 EDT 看到对表模型所做的更新。但即使不使列表不稳定,更新似乎也有效。以下是我的代码
import java.awt.BorderLayout;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
JFrame frame = new JFrame("FrameDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyTableModel dm = new MyTableModel();
frame.getContentPane().add(new JScrollPane(new JTable(dm)), BorderLayout.CENTER);
new Thread(new Runnable() {
int count = 0;
@Override
public void run() {
while (true) {
dm.addElement(count++);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
frame.pack();
frame.setVisible(true);
}
class Row {
private String name;
private String value;
public Row(String name, String value) {
super();
this.name = name;
this.value = value;
}
}
class MyTableModel extends AbstractTableModel {
private List<Row> rows = new ArrayList<Test.Row>();
@Override
public int getRowCount() {
return rows.size();
}
@Override
public int getColumnCount() {
return 2;
}
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
if (columnIndex == 0) {
return rows.get(rowIndex).name;
} else if (columnIndex == 1) {
return rows.get(rowIndex).value;
} else {
throw new IllegalArgumentException();
}
}
private void addElement(int i) {
rows.add(new Row("Name" + i, "Vlaue0" + i));
fireTableRowsInserted(rows.size() - 1, rows.size() - 1);
}
@Override
public String getColumnName(int column) {
return column == 0 ? "Name" : "Value";
}
}
}
在将rows
变量标记为 volatile 之前,我想知道如果我已经可以工作,为什么我必须这样做。而且,上面链接的问题也提到了 synchronized
关键字。我不明白如何使用 synchronized
关键字修复线程看不到最新值的问题。对此的任何解释也表示赞赏。
最佳答案
将调用 dm.addElement(count++);
改为 SwingUtilities.invokeAndWait()
来自javadoc
* Causes <code>doRun.run()</code> to be executed synchronously on the
* AWT event dispatching thread. This call blocks until
* all pending AWT events have been processed and (then)
* <code>doRun.run()</code> returns. This method should
* be used when an application thread needs to update the GUI.
* It shouldn't be called from the event dispatching thread.
* Here's an example that creates a new application thread
* that uses <code>invokeAndWait</code> to print a string from the event
* dispatching thread and then, when that's finished, print
* a string from the application thread.
* <pre>
* final Runnable doHelloWorld = new Runnable() {
* public void run() {
* System.out.println("Hello World on " + Thread.currentThread());
* }
* };
*
* Thread appThread = new Thread() {
* public void run() {
* try {
* SwingUtilities.invokeAndWait(doHelloWorld);
* }
* catch (Exception e) {
* e.printStackTrace();
* }
* System.out.println("Finished on " + Thread.currentThread());
* }
* };
* appThread.start();
* </pre>
关于java - 从基于 Swing 的应用程序中的线程(ETC 除外)接收更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28893034/