0

我有一个LinkedList<JLabel>并在线程上使用它来添加或删除它们JPanel,问题是有时会发生异常并且应用程序崩溃。在他们谈论同步我的列表的一些帖子中,其他人说我应该有一个迭代器,所以我有点困惑。

我将添加一些代码以使其易于理解:

public class MyPanel extends JPanel {

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

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

这是链接列表被初始化的地方,现在我有 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

您必须使用 anIteratorListwhile 迭代中删除:

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

您不能在多线程上下文中使用 LinkedList,而是使用 java.util.concurrent.CopyOnWriteArryayList

于 2013-09-21T16:25:02.770 回答
0

如果在迭代ConcurrentModificationException时修改了数据结构(添加或删除内容),迭代器将抛出异常。

要解决此问题,您可以克隆标签结构并在克隆上进行迭代。

于 2013-09-21T16:07:29.083 回答