我应该如何管理对ArrayDeque的多线程并发访问?

时间:2011-08-13 04:25:55

标签: java concurrency jlist deque

My Swing GUI显示由后台线程顺序删除的项目的JList。

根据AbstractListModel的合约,JList后面是ArrayDeque<Card>,myHopper,实现myHopper.getSize()myHopper.getElementAt()

后台线程使用myHopper.poll()删除项目。

毫不奇怪,我目前正在使AWT数组索引超出范围。

我应该怎么做才能在EDT线程和后台线程之间正确同步对myList的访问?我见过对Collections.synchronizedList(arrayList)的引用,但我认为这不符合我的ArrayDeque。

4 个答案:

答案 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)