What is the best way to achieve this thread / event behavior in Java?

I have a thread (Runnable) that starts a number of other threads (Runnables). When each child thread ends, it needs to raise an event (or something similar) and return a notification to the parent thread. I do not see any events in Java (ala C #). I was hoping I could just subscribe to the parent object "I finished the event", but it seems like I cannot do this. How do you suggest me to do this?

thanks

+4
source share
5 answers

Java has a CountDownLatch in its thread library. Create a CountDownLatch and initialize it with the number of threads you are about to run. When you create your threads, you must give them a latch, and each thread will signal this when it ends. Your main thread will be blocked until all worker threads are finished.

With CountDownLatch you will get a contactless connection with your threads.

Directly from the Java documentation:

  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() { ... } } 

http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/CountDownLatch.html

+4
source

You create an interface for the parent

 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 ); } } 
+3
source

You can use the observer pattern option. Add a callback function to the parent element (e.g. void finished(SomeArgs args) ) and create each child element with a link to its parent element. When the child is finished, call his parent finished() method.

Make sure the callback is thread safe!

+2
source

It does not use events, but I am just one of them, I am sure that many ways to do this. A quick warning: to do this, you will need to include the Runnable object in the Thread object or change your interface to have any isStopped () method in your Runnable that returns whether your Runnable was still running.

Perhaps the parent thread keeps track of all the child threads in the list. When the child thread ends, put the value that it calculates in some field, say, the result, and create a method called getResult ().

Periodically iterate over the parent thread through the list and check if the thread is stopped. If you create a Runnable to Thread object, there is a method called isAlive () to determine if the thread is stopped. If it is, call getResult () and do whatever.

In the parent thread you can do this:

 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 } 
0
source

The java.util.concurrent.ThreadPoolExecutor class does what you need. It executes multiple threads and provides a hook that is called after each Runnable completes. Basically you can create an anonymous subclass and override afterExecute . Like this:

 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 } }; 

Here is a complete example:

 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 } } }; } } 

Exit:

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

Source: https://habr.com/ru/post/1303259/


All Articles