在Java中实现这种线程/事件行为的最佳方法是什么?

在Java中实现这种线程/事件行为的最佳方法是什么?,java,multithreading,events,Java,Multithreading,Events,我有一个线程(Runnable),它启动许多其他线程(Runnable)。当每个子线程完成时,它需要引发一个事件(或类似事件),并向父线程返回一个通知。我在Java(ala C#)中看不到任何事件-我希望我可以在父对象中订阅子对象的“我完成了事件”,但似乎我做不到。你建议我如何做到这一点 谢谢您可以在上使用变体。在父级中实现回调函数(例如void finished(SomeArgs args)),并使用对其父级的引用构造每个子级。当子对象完成时,让它调用父对象的finished()方法 确保回调

我有一个线程(Runnable),它启动许多其他线程(Runnable)。当每个子线程完成时,它需要引发一个事件(或类似事件),并向父线程返回一个通知。我在Java(ala C#)中看不到任何事件-我希望我可以在父对象中订阅子对象的“我完成了事件”,但似乎我做不到。你建议我如何做到这一点


谢谢

您可以在上使用变体。在父级中实现回调函数(例如
void finished(SomeArgs args)
),并使用对其父级的引用构造每个子级。当子对象完成时,让它调用父对象的
finished()
方法


确保回调是线程安全的

在父对象上创建接口

public interface EventListener  {
    void trigger(Object event); 
} 

public class Parent implements EventListener { 
    public synchronized void trigger(Object event) { 
        // process events. 
    }
}

public class Child implements Runnable { 
    private final EventListener listener; 

    public Child(EventListener listen) { 
       listener = listen; 
    }  

    public void run () {
      //do stuff
      listener.trigger( results ); 
    } 
}

这不使用事件,但我相信这只是实现这一点的许多方法之一。快速警告:要使其起作用,您需要将Runnable强制转换为Thread对象,或者修改接口以在Runnable上使用某种isStopped()方法,这将返回Runnable是否仍在运行

您可以让父线程在列表中跟踪其所有子线程。当一个子线程完成时,将它计算的值放在某个字段中,例如result,并生成一个名为getResult()的方法

让父线程定期遍历列表并检查线程是否已停止。如果将Runnable强制转换为Thread对象,则会有一个名为isAlive()的方法来判断线程是否已停止。如果有,调用getResult()并执行任何操作

在父线程中,可以执行以下操作:

Boolean running = true;
while (running) {
    //iterate through list
    //if stopped, get value and do whatever
    //if all the child threads are stopped, stop this thread and do whatever
    Thread.sleep(1000); //makes this parent thread pause for 1 second before stopping again
}

Java的线程库中有一个
CountDownLatch
。创建一个
倒计时闩锁
,并用要运行的线程数初始化它。当你创建你的线程时,你应该给它们闩锁,当它完成时,每个线程都会发出信号。主线程将阻塞,直到所有工作线程完成

使用
CountDownLatch
可以实现与线程的无锁通信

直接来自Java文档:

 class Driver { // ...
   void main() throws InterruptedException {
     CountDownLatch startSignal = new CountDownLatch(1);
     CountDownLatch doneSignal = new CountDownLatch(N);

     for (int i = 0; i < N; ++i) // create and start threads
       new Thread(new Worker(startSignal, doneSignal)).start();

     doSomethingElse();            // don't let run yet
     startSignal.countDown();      // let all threads proceed
     doSomethingElse();
     doneSignal.await();           // wait for all to finish
   }
 }

 class Worker implements Runnable {
   private final CountDownLatch startSignal;
   private final CountDownLatch doneSignal;
   Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
      this.startSignal = startSignal;
      this.doneSignal = doneSignal;
   }
   public void run() {
      try {
        startSignal.await();
        doWork();
        doneSignal.countDown();
      } catch (InterruptedException ex) {} // return;
   }

   void doWork() { ... }
 }
类驱动程序{/。。。
void main()抛出InterruptedException{
CountDownLatch startSignal=新的CountDownLatch(1);
CountDownLatch doneSignal=新的CountDownLatch(N);
for(inti=0;i

java.util.concurrent.ThreadPoolExecutor
执行您需要的操作。它执行许多线程,并提供一个钩子,在每次
Runnable
完成后调用该钩子。基本上,您可以创建一个annonymous子类,并在执行后重写
。像这样:

ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 20, 5,
        TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(50)) {
    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        // do your callback stuff here
    }
};

您可以加入一个线程,但这将阻止,直到该线程完成。如果可以让代码使用Executor框架,那么另一个选项是让其他可运行任务代替。然后,您重写类的
FutureTask
方法(通过您编写的子类)以发出任务完成的信号。@Chris Jester Young:这应该是一个答案,而不是注释。@MalcomTucker您应该为此使用CoutnDownLatch。。。更多详细信息,请参见我的答案。@Aaron:通常我会将此作为答案发布,但我不想花时间(因为我正在工作:-P)查找Executor、FutureTask等的链接,这是我通常写答案的方式。所以,我想我应该给其他人一个快速的提示,让他们带着我跑。:-)(请随意把我的评论充实成一个真实的答案。我不介意。)不,我绝对不想这样做,我有潜在的数千个线程…注意同步触发器方法-这很重要。父类的其余部分对于trigger()也必须是线程安全的;子线程可以直接了解父线程并调用它的一个方法。CountDownLatch是专门为线程之间的通信而设计的:不需要锁定。
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Main {
    private static int ready = 0;

    public static void main(String[] args) throws InterruptedException {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 20, 5,
                TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(50)) {
            @Override
            protected void afterExecute(Runnable r, Throwable t) {
                ready++;
            }
        };

        for (int n = 0; n < 5; n++)
            executor.execute(createTask());
        executor.shutdown();

        while(ready < 5) {
            System.out.println("Ready: " + ready);
            Thread.sleep(100);
        }

        System.out.println("Ready with all.");
    }

    private static Runnable createTask() {
        return new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep((long) (Math.random() * 1000));
                } catch (InterruptedException e) {
                    // ignore exception to make debugging a little harder
                }
            }
        };
    }

}
Ready: 0
Ready: 1
Ready: 1
Ready: 3
Ready: 3
Ready: 4
Ready: 4
Ready: 4
Ready: 4
Ready with all.