0

私は を持っていて、LinkedList<JLabel>それをスレッドで使用して に追加または削除しますJPanel。問題は、例外が発生してアプリケーションがクラッシュすることがあるということです。リストの同期について話している投稿もあれば、イテレータが必要だと言う人もいるので、少し混乱しています。

理解しやすくするためにいくつかのコードを追加します。

public class MyPanel extends JPanel {

(...)
private LinkedList<JLabel> labels;
(...)

public MyPanel(Color corLabel, Color back, Font text) {
(...)
labels = new LinkedList<>();
(...)
}

これは、Linked List が初期化される場所です。1 つのメソッドと 1 つのスレッドがそれを使用しています。

 public void addMensagem(MensagemParaEcra msg) {

    JLabel lbl = new JLabel();
    lbl.setText(("- " + msg.getTexto() + " -"));
    lbl.setForeground(color);
    lbl.setFont(textFont);
    lbl.setOpaque(true);
    lbl.setBackground(backg);

    labels.add(lbl);
    MyPanel.this.add(lbl);

}

これは、ラベルを構成してパネルとリンクリストに追加するだけです

private void start() {
    final Runnable running = new Runnable() {
        @Override
        public void run() {
            MyPanel.this.repaint();

        }
    };

    Thread t = new Thread() {
        public void run() {
            while (true) {
                // for each label
                for (JLabel lb : labels) {
                    if (lb.getLocation().x + lb.getWidth() < 0) {
                        if (msgsRemover.isEmpty() == true) {
                            //remove the label if she is out of the monitor
                            MyPanel.this.remove(lb);
                            // and add the label
                            MyPanel.this.add(lb);

                            MyPanel.this.repaint();
                            MyPanel.this.validate();
                        } else {
                            // if there is some message to remove
                            for (String s : msgsRemover) {
                                if (lb.getText().toString().equals(s)) {
                                    // remove the visual label   
                                    MyPanel.this.remove(lb);
                                    MyPanel.this.repaint();
                                    // remove the message that need to be removed from the linked list
                                    msgsRemover.remove(s);
                                    // remove the label from the JLabel list
                                    labels.remove(lb);

                                } else {
                                    // if there is no message to be removed, they will just continue
                                    // going to the end of the queue
                                    MyPanel.this.remove(lb);
                                    MyPanel.this.add(lb);

                                    MyPanel.this.repaint();
                                    MyPanel.this.validate();
                                }
                            }

                        }

                    }
                    lb.setLocation(lb.getLocation().x - 3, 0);

                }
                repaint();
                try {
                    SwingUtilities.invokeAndWait(running);
                    sleep(30);
                } catch (InterruptedException ex) {
                    Logger.getLogger(MyPanel.class.getName()).log(Level.SEVERE, null, ex);
                } catch (InvocationTargetException ex) {
                    Logger.getLogger(MyPanel.class.getName()).log(Level.SEVERE, null, ex);
                }

            }
        }
    };
    t.start();
}

これはエラーが発生したコードです。プログラムがクラッシュすることがあり、問題が発生していると言われています。

for (JLabel lb : labels)

スタックトレース:

Exception in thread "Thread-2" java.util.ConcurrentModificationException
at java.util.LinkedList$ListItr.checkForComodification(LinkedList.java:953)
at java.util.LinkedList$ListItr.next(LinkedList.java:886)
at smstest.MyPanel$3.run(MyPanel.java:110)

だから、私はイテレータを使用して動作していますが、今は別の問題に直面しています...コードがあります:

for(Iterator<String> it2 = msgsRemover.iterator(); it.hasNext();){
                                String s = it2.next();

                                if (lb.getText().toString().equals(s)) {
                                    // remove the visual label   
                                    MyPanel.this.remove(lb);
                                    MyPanel.this.repaint();
                                    // remove the message that need to be removed from the linked list
                                    it2.remove();
                                    // remove the label from the JLabel list
                                    it.remove();

だから、今私の問題は String s = it2. next(); にあります。スタックトレースは次のとおりです。

Exception in thread "Thread-2" java.util.NoSuchElementException
at java.util.LinkedList$ListItr.next(LinkedList.java:888)
at smstest.MyPanel$3.run(MyPanel.java:131)

どうすれば解決できますか?前もって感謝します

4

3 に答える 3

3

反復中Iteratorに a から削除するには、 an を使用する必要があります。List

final Iterator<JLabel> labelIter = labels.iterator();
while(labelIter.hasNext()) {
    final JLabel label = labelIter.next();
    //do stuff with label
    labelIter.remove();
}

さらに重要なことは、あなたがやろうとしていることができないということです。Swing はスレッドセーフではありません。

コンポーネントを EDT から切り離して変更することはできません。

続行する前にこれをお読みください。そうしないと、競合の危険性と一見ランダムな GUI の問題が発生することになります。

于 2013-09-21T16:20:30.523 に答える
0

イテレータConcurrentModificationExceptionは、反復中にデータ構造が変更された場合 (何かを追加または削除した場合) にスローします。

この問題を解決するには、ラベル構造を複製して複製を反復します。

于 2013-09-21T16:07:29.083 に答える
0

マルチスレッド コンテキストでは LinkedList を使用できません。代わりに java.util.concurrent.CopyOnWriteArryayList を使用してください。

于 2013-09-21T16:25:02.770 に答える