大家好: 基本上我需要在用户按下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();
}
}
答案 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()。