2010-12-17 182 views
3

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

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

什么数据类型是eventList? (实际上是一个java.util.ArrayList <...>)尝试java.util.concurrent包中的集合,看看是否有帮助。仅供参考,我通常使用某种类型的互斥体(例如java.util.concurrent.ReentrantLock)来处理这种情况。 – Merky 2010-12-17 16:38:09

回答

1

问题是你正在修改一个List并同时循环它。对于标准列表,这个行为是未定义的,并且抛出异常。 查看java.util.concurrent软件包的多线程使用安全集合。

1

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

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

0

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

+0

我怀疑sychronized可能是解决方案。任何人都可以告诉我如何在代码中实现它。 – Jack 2010-12-17 17:18:03

+0

@ user528995,请显示,你如何声明并初始化你eventList – osgx 2010-12-17 17:31:39

+0

这是错误的。异常发生在单个线程上,实际上与线程无关。这个名字是用词不当。事实上,正如其他几位人士所说的那样,底层列表正在发生变化,同时你正在迭代它。 – Robin 2010-12-17 18:19:36

0

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

但是,由于您有要处理的事件列表,我宁愿遵循另一种模式。将列表替换为并发队列(LinkedBlockingQueue就是一个很好的例子),然后,当您需要终止线程时,而不是设置布尔标志,您只需清除队列并在那里放置终止事件。事件处理线程在处理完每个事件之后,应该检查它是否是一个终止事件(通过使用instanceof或某种类型的getEventClass()方法),如果是,则打破循环。请注意,由于您的线程有像Thread.sleep()和可能的waitWhileSuspended()这样的冗长操作(不管它是什么,尽管在切换到阻塞队列后可能不再需要它),您需要中断()在将终止事件放入队列后处理线程,并根据应用程序逻辑处理事件处理线程中的InterruptedException。例如,如果Thread.sleep()被中断或者可能继续下一次迭代,则应决定是否处理事件。

0

我会做的事情是这样的

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

,然后就调用中断()时,我想停止线程。