3

私の Swing GUI は、バックグラウンド スレッドによって順次削除される項目の JList を表示します。

JList の背後には、AbstractListModel のコントラクトに従って、およびArrayDeque<Card>を実装する myHopper があります。myHopper.getSize()myHopper.getElementAt()

バックグラウンド スレッドは、 を使用してアイテムを削除しますmyHopper.poll()

驚くことではありませんが、現在、AWT 配列インデックスの範囲外の例外が発生しています。

EDT スレッドとバックグラウンド スレッドの間で myList へのアクセスを適切に同期するにはどうすればよいですか? への参照を見Collections.synchronizedList(arrayList)たことがありますが、それが私の ArrayDeque に適合するとは思いません。

4

4 に答える 4

5

ArrayDequeの代わりにLinkedBlockingDequeを使用してみましたか?

于 2011-08-13T04:27:27.700 に答える
3

私の質問に対する簡単な答えは、「できません。EDT 以外のスレッドから Swing コンポーネント [およびそのモデルを含む] にアクセスしようとしてはいけません。」

この投稿は、私が最終的にどのように問題を解決したかを示しています。ワーカー スレッドは JList のモデルからアイテムをプルする必要があり、それを使用して EDTinvokeAndWait()での作業をスケジュールし、そのタスクが完了するまで待機してから続行します。

同期された LinkedBlockingDeque を使用してもうまくいきませんでした。これは、GUI コンポーネントを更新するときに、EDT が Deque インターフェイスに対してアトミックでない一連の呼び出しを行うためだと思われます。別のスレッドによる呼び出し のモデルへの変更は、EDT が行っている安定性の仮定を破壊する可能性があります。

(おそらく、これは、Swing のドキュメント全体に表示される「警告: Swing はスレッドセーフではありません」という永続的なメッセージによって示唆されていることです。)

于 2011-08-18T04:56:14.410 に答える
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");
        }
    }

}
于 2011-08-13T19:43:51.027 に答える
0

代わりに SwingWorker を使用して操作を実行してください。

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

于 2011-08-13T10:55:53.600 に答える