Как мне управлять многопоточным параллельным доступом к ArrayDeque? - PullRequest
3 голосов
/ 13 августа 2011

Мой Swing GUI отображает JList элементов, которые последовательно удаляются фоновым потоком.

За JList находится ArrayDeque<Card>, myHopper, реализующий myHopper.getSize() и myHopper.getElementAt(), в соответствии с контрактом AbstractListModel.

Фоновый поток удаляет элементы, используя myHopper.poll().

Не удивительно, что в настоящее время я получаю индекс массива AWT из-за исключительных ситуаций.

Что мне следует сделать, чтобы правильно синхронизировать доступ к myList между потоком EDT и моим фоновым потоком?Я видел ссылки на Collections.synchronizedList(arrayList), но я не думаю, что это соответствует моему ArrayDeque.

Ответы [ 4 ]

5 голосов
/ 13 августа 2011

Вы пытались использовать LinkedBlockingDeque вместо ArrayDeque?

3 голосов
/ 18 августа 2011

Краткий ответ на мой вопрос: «Вы не можете: вы никогда не должны пытаться получить доступ к компоненту Swing [и включая его модель] из какого-либо потока, кроме EDT».

Этот пост показывает, как я в конечном итоге решил проблему. Рабочий поток должен извлечь элемент из модели JList и делает это с помощью invokeAndWait() для планирования этой работы на EDT , а затем ждет, пока эта задача будет выполнена, и затем продолжает.

Использование синхронизированного LinkedBlockingDeque не сработало, и я подозреваю, что это связано с тем, что EDT выполняет неатомные серии вызовов интерфейса Deque при обновлении компонента GUI. Любое изменение в модели между вызовами другим потоком может разрушить любые предположения о стабильности, которые делает EDT.

(Возможно, именно об этом намекает постоянное « Предупреждение: Swing не безопасен для потоков», который встречается в документации Swing.)

1 голос
/ 13 августа 2011

Следующий код хорошо работает для меня и может дать вам несколько идей.

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

}
0 голосов
/ 13 августа 2011

Выполняйте свои операции, используя SwingWorker.

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

...