2011-05-29 40 views
2

我有一个程序创建了一个类的数百个实例,每个实例都监听另一个线程,这个线程只是在一个定时的时间表上触发一个事件(以便它们都以相同的速度执行)。我想让数百个实例中的每一个都成为它自己的线程,这样当事件被触发时,它们都可以并行工作。对我来说有意义的是让这些类扩展Thread类,然后在它们内部包含这些代码...让线程从java中的事件监听器运行?

public class IteratorStepListener implements StepEventListener { 
     public void actionPerformed(ActionEvent e) { 
      start(); 
     } 
} 

public void run() { 
     doStuff(); 
} 

虽然这似乎不起作用。很明显,我不了解这里的基本内容。什么是正确的方法来做到这一点?

回答

3

听起来事件将被多次触发......但您无法多次启动同一个线程。

这听起来像你的听众应该实现的接口,而是直接在actionPerformed启动一个线程(或更好,使用Executor,以便它可以使用一个线程池)。因此,代替目前的实现,你可以使用:

// Assuming the listener implements runnable; you may want to 
// delegate that to a separate class for separation of concerns. 
public void actionPerformed(ActionEvent e) {    
    new Thread(this).start(); 
} 

public void actionPerformed(ActionEvent e) {    
    executor.execute(this); 
} 
+0

这正是我所错过的。我把我的东西与线程混淆了,没有任何东西来自它。我已经添加了一个Executor,现在一切都运行得更加顺利。谢谢大家回复,你救了我几个小时的头痛。 – Mike 2011-05-29 23:38:12

3

我想是每个几百实例的是它自己的线程,这样当一个事件被解雇,他们都可以并行工作。

我不认为这是一个好方法。

  • 除非你有数百个处理器,线程不能可能并行的所有工作。您将最终获得一次一个(每个处理器一个)运行它们的线程,或者在处理器之间进行时间分片。

  • 即使在非活动状态下,每个线程实际上都会关联JVM资源的一个重要部分。 IIRC,默认的堆栈大小约为1 Mbyte。

  • 您问题中的示例代码显示线程上调用start()的事件。不幸的是,您只能在线程上拨打start()一次。一旦线程终止,它不能重新启动。

一个更好的方法是创建一个有界线程池的执行,并让每个事件引起一个新的任务提交给执行者。类似这样的:

ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maxPoolSize, 
    keepAliveTime, timeUnit, workQueue); 

... 

public class IteratorStepListener implements StepEventListener, Runnable { 
    public void actionPerformed(ActionEvent e) { 
     executor.submit(this); 
    } 

    public void run() { 
     doStuff(); 
    } 
} 
+0

该解决方案允许同一个实例由多个线程同时执行。此外,它可能会导致乱序事件处理。它不是*数百个实例是它自己的线程*,我知道它可能是显而易见的,只是指出 – bestsss 2011-05-29 20:39:32

0

你不能在Java中使用类似线程。这是因为Java线程直接映射到底层操作系统线程(至少在我知道的JVM实现上),而OS线程无法像这样扩展。经验法则是,您想要在应用程序中将线程总数保持在几百或几百个。几百个可能是好的。数千人通常会遇到问题,具体取决于您使用的硬件。

像你描述的使用线程是类似的Erlang语言,例如有效的实施战略。同时,如果你被卡住的Java这段时间,创造一个共享线程池,并提交您的任务给这个,而不是让所有的任务同时运行可能是一个很好的选择。在这种情况下,你可以选择合适数量的线程(最好的数字取决于任务的性质,如果你不知道,CPU核心可用的次数2是一个好的开始),并且同时运行这些任务。

如果你绝对需要同时进行所有任务,它可能会有点复杂,但这也是可行的。

3

好的,第一件事:克服你的数百个线程并行运行的概念。在最好的情况下,他们将同时运行,即时间分割的。当你进入数百个线程时,你会看到调度算法的方向开始发光;在成千上万的人中,他们会抽烟并最终占领,而且你不会再有线索。现在,这就是说,我们没有足够的代码来理解你真的在做什么,但我注意到的一件事是你似乎没有制作新的线程。请记住,线程是一个对象;启动一个线程的正规途径是

Thread t = new Thread(Runnable r); 
    t.run(); 

它看起来像什么,你想run()同一线程一遍又一遍;这种方式就是疯狂。看看Wiki上的Event Driven Programming。如果你真的想有一个独立的线程来处理每个事件,你需要一个像这样的方案(伪代码):

processEvents: function 
    eventQueue: queue of Events 
    event: implements Runnable 

    -- something produces events and puts them on the queue 

    loop -- forever 
    do 
     Event ev := eventQueue.front 
     new Thread(ev).run(); 
    od 
end -- processEvents    
+0

*“克服了你的数百个线程将并行运行的想法*”这不像是科幻小说。我们有并行计算,其中一些项目并行运行数十万个处理器。我们有多处理器服务器,以及新一代100核处理器。我们拥有拥有数千个处理器的超级计算机。欢迎来到未来。 (OP可能不是针对这样的硬件,但我们不要传播错误信息。) – 2015-07-28 11:37:27

+0

当您发现一台将在高度并行机器上使用数千个处理器的JVM时,请告知我。 – 2015-07-28 15:58:47