My Swing GUI显示由后台线程顺序删除的项目的JList。
根据AbstractListModel的合约,JList后面是ArrayDeque<Card>
,myHopper,实现myHopper.getSize()
和myHopper.getElementAt()
。
后台线程使用myHopper.poll()
删除项目。
毫不奇怪,我目前正在使AWT数组索引超出范围。
我应该怎么做才能在EDT线程和后台线程之间正确同步对myList的访问?我见过对Collections.synchronizedList(arrayList)
的引用,但我认为这不符合我的ArrayDeque。
答案 0 :(得分:5)
您是否尝试过使用LinkedBlockingDeque代替ArrayDeque?
答案 1 :(得分:3)
对我的问题的简短回答似乎是“你不能:你绝不能尝试从EDT以外的任何线程访问Swing组件[包括其模型]。”
This post显示了我最终如何解决问题。工作线程需要从JList的模型中提取项目,并使用invokeAndWait()
在EDT上安排该工作 ,然后等待该任务完成,然后继续。
使用同步的LinkedBlockingDeque不起作用,我怀疑这是因为EDT在更新GUI组件时对Deque接口进行非原子系列调用。由另一个线程对调用之间的模型进行的任何更改都可能破坏EDT正在进行的任何稳定性假设。
(也许这就是整个Swing文档中出现的持久性“警告: Swing不是线程安全”所暗示的内容。)
答案 2 :(得分:1)
以下代码适合我,可能会给你一些想法。
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;
import java.util.Timer;
public class JListDemo {
public static void main(String[] args) {
final MyListModel model = new MyListModel();
// set up a background task to periodically purge items from the list
java.util.Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
String item = model.poll();
if (item != null) {
System.out.println("Removed " + item + " from list");
} else {
System.out.println("Nothing to remove off list, click 'Add Item' button to add more");
}
}
}, 1000, 2000);
JList list = new JList(model);
// Add a button to add new items to the list
JButton button = new JButton("Add Item");
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
model.offer(new Date().toString());
}
});
JFrame frame = new JFrame("JList Demo");
frame.add(list);
frame.add(button, BorderLayout.SOUTH);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(200, 200);
frame.setVisible(true);
}
private static class MyListModel extends DefaultListModel {
private final ArrayDeque<String> dq = new ArrayDeque<String>();
public synchronized String poll() {
String head = dq.poll();
if (head != null) {
removeElementAt(0);
}
return head;
}
public synchronized void offer(String item) {
dq.offer(item);
insertElementAt(item, getSize());
System.out.println("Added " + item + " to list");
}
}
}
答案 3 :(得分:0)
使用SwingWorker执行操作。
http://download.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html