【问题标题】:How should I manage multithreaded concurrent access to an ArrayDeque?我应该如何管理对 ArrayDeque 的多线程并发访问?
【发布时间】:2011-08-13 04:25:54
【问题描述】:

我的 Swing GUI 显示一个 JList 项目,这些项目正被后台线程按顺序删除。

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

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

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

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

【问题讨论】:

    标签: java concurrency jlist deque


    【解决方案1】:

    您是否尝试过仅使用 LinkedBlockingDeque 而不是 ArrayDeque?

    【讨论】:

    • 我能够在编译器没有任何抱怨的情况下替换它,我怀疑对于双端队列来说,链表可能比数组更好;但是,我仍然让 AWT 数组索引超出范围异常。我确实找到了stackoverflow.com/questions/3440360/…,它表明应该永远在除 EDT 之外的任何线程上修改模型。有点道理,虽然我说不出为什么。回到绘图板......
    【解决方案2】:

    对我的问题的简短回答似乎是“你不能:你绝不能尝试从 EDT 以外的任何线程访问 Swing 组件 [包括其模型]。”

    This post 展示了我最终是如何解决这个问题的。工作线程需要从 JList 的模型中提取项目,并使用 invokeAndWait() 在 EDT 上调度该工作,然后等待该任务完成,然后继续。 p>

    使用同步的 LinkedBlockingDeque 不起作用,我怀疑这是因为 EDT 在更新 GUI 组件时对 Deque 接口进行了非原子的系列调用。 调用之间由另一个线程对模型进行的任何更改都可能破坏 EDT 所做的任何稳定性假设。

    (也许这就是在整个 Swing 文档中出现的持久性“警告: Swing 不是线程安全的”所暗示的。)

    【讨论】:

      【解决方案3】:

      以下代码对我来说效果很好,可能会给你一些想法。

      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");
              }
          }
      
      }
      

      【讨论】:

        【解决方案4】:

        改为使用 SwingWorker 执行您的操作。

        http://download.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html

        【讨论】:

        • 我可能是错的,但我认为这不会有帮助。正如我所理解的那样,如果 EDT 以外的 任何 线程修改了列表模型(即使是具有并发保护的线程),它也会在 EDT 重绘 GUI 期间冒这样做的风险。如果重绘需要对列表模型的多次访问,那么另一个线程的恶意修改可能会破坏 GUI 重绘例程所做的任何稳定性假设。这只是一个猜测;我想知道是否还有其他人可以阐明...
        猜你喜欢
        • 1970-01-01
        • 2011-07-03
        • 1970-01-01
        • 1970-01-01
        • 2011-04-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多