Java终止或终止一个线程

时间:2010-12-17 16:30:54

标签: java concurrency

大家好: 基本上我需要在用户按下Terminate按钮时终止或停止线程运行。此线程循环遍历arraylist并在JTextArea上显示每个事件。要求是当用户按下Terminate按钮时,我需要终止正在运行的线程,同时向arraylist添加一个新的“Terminating”事件并让它再次运行以打印“编程终止”。下面的代码类似“工作”,但我在控制台中得到了java.util.ConcurrentModificationException。有人可以帮忙吗?

public void startEvents()
    {
        terminate = false;
        worker = new Thread(new Runnable()
        {
            public void run()
            {
                Iterator<Event> it = eventList.iterator();

                while (it.hasNext())
                {
                    waitWhileSuspended();
                    terminatEvents();
                    Event ev = it.next();
                    try
                    {
                        Thread.sleep(ev.getDelayTime());
                    } catch (InterruptedException e1)
                    {
                        e1.printStackTrace();
                    }
                    jTextArea.append(ev.toString() + "\n");
                    it.remove();
                }
                jbStart.setEnabled(true);
                jmiStart.setEnabled(true);
                jbRestart.setEnabled(true);
                jmiRestart.setEnabled(true);
            }
        });
        worker.start();
    }
public void terminatEvents()
    {
        while(terminate)
        {
            Thread.yield();
            eventList.clear();
            eventList.add(new Terminate(delayTime));
            startEvents();

        }
    }

5 个答案:

答案 0 :(得分:1)

问题在于您正在修改List并同时循环遍历它。使用标准列表时,此行为未定义,这会抛出异常。 查看java.util.concurrent包中可以安全使用多线程的集合。

答案 1 :(得分:1)

看起来您正在修改列表(清除它然后添加新的Terminate事件),同时迭代它。这就是你获得ConcurrentModificationException

的原因

我建议你在你的线程对象中简单地使用terminate()方法,并调用它来停止打印事件列表然后打印新的Terminate事件,而不使用列表。

答案 2 :(得分:0)

您可以从2个主题更改Collection。默认情况下,集合是不同步的,您应该使用“Synchronized”关键字或切换到synchronizedCollection http://download.oracle.com/javase/1.4.2/docs/api/java/util/Collections.html#synchronizedCollection(java.util.Collection)

答案 3 :(得分:0)

停止线程的常用方法是设置一些volatile布尔标志,我看到你的情况是terminate字段。要遵循正常模式,您应该在while (!terminated && ...)之类的每次迭代中检查此标志。设置终止标志的线程也应该将你的最终事件放在某个字段中,比如,在循环之后应该检查的terminateEvent,如果此时终止为真(也就是说,如果线程被终止而不是正常结束)。当然,应该同步对terminateEvent的访问(注意volatile可能在这里不起作用)。

但是,由于您有要处理的事件列表,我宁愿遵循另一种模式。用并发队列替换列表(LinkedBlockingQueue是一个很好的例子)然后,当你需要终止线程时,不要设置布尔标志,而只需清除队列并将终止事件放在那里。处理完每个事件后,事件处理线程应该检查是否是终止事件(通过使用instanceof或某种getEventClass()方法),如果是,则只需打破循环。

请注意,由于你的线程有冗长的操作,比如Thread.sleep()和可能的waitWhileSuspended()(不管它是什么,虽然在切换到阻塞队列后你可能不再需要它),你需要打断()你的线程将终止事件放入队列后的线程,并在事件处理线程中相应地处理应用程序逻辑中的InterruptedException。例如,如果Thread.sleep()被中断或者可能继续下一次迭代,您应该决定是否处理事件。

答案 4 :(得分:0)

我这样做的方式是

public void run() {
  while (!isInterrupted()) {
    // actual working code goes here
  }
} // end of life for this thread

然后在我想停止线程时调用interrupt()。