如果 Swing 模型的 getter 不是线程安全的,你如何处理它们?
众所周知,更新 Swing GUI 必须仅在 EDT 中完成。较少宣传的是从GUI读取内容必须/也应该在EDT中完成。例如,让我们以ButtonModel的isSelected()方法为例,该方法告诉(例如)ToggleButton的状态(“down”或“up”)。
在我见过的每个示例中,都从主线程或任何线程中自由查询。但是当我查看DefaultButtonModel的实现时,它没有同步,并且值不是易失性的。因此,严格来说,如果从设置垃圾的线程(即用户按下按钮时的EDT)以外的任何其他线程读取垃圾,则可能会返回垃圾。还是我错了?isSelected()
isSelected()
我最初想到这一点时,对布洛赫的有效Java中的第66项感到震惊,这个例子:
public class StopThread {
private static boolean stopRequested;
public static void main(String[] args) throws InterruptedException {
Thread backgroundThread = new Thread(new Runnable() {
public void run() {
int i = 0;
while(!stopRequested) i++;
}
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
stopRequested = true;
}
}
与看起来相反,该程序永远不会终止,至少在某些机器上。从主线程更新标志对后台线程不可见。这种情况可以通过同步的getters和setters来修复,或者通过设置标志 。stopRequested
volatile
所以:
- 在 EDT 之外查询 Swing 模型的状态(严格来说)是否是错误的?
- 如果没有,怎么会这样?
- 如果是,你如何处理它?靠运气,还是靠一些聪明的解决方法?InvokeAndWait?