2

I want a method that runs 2 or more methods in separate threads. I want be sure that method won't finish before all threads are done.

Donato Szilagyi
  • 4,279
  • 4
  • 36
  • 53
damienix
  • 6,463
  • 1
  • 23
  • 30

4 Answers4

6

The best approach is to utilize the Executor Service API to manage a thread pool instead of starting an open-ended number of threads on your own.

ExecutorService pool = Executors.newCachedThreadPool();
for (Runnable r : new Runnable[] {
    new R() { void r() { myMethod1(); }},
    new R() { void r() { myMethod2(); }},
})
  pool.execute(r);
pool.shutdown();
pool.awaitTermination(60, TimeUnit.SECONDS);

abstract class R implements Runnable
  public final void run() { r(); }
  abstract void r();
}

Note that it is not advisable to insist on every method running in its own, separate thread. Threads are quite heavyweight (each allocating a complete call stack) and performance actually decreases as the thread count increases far beyond the number of available processor cores.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
  • what is a benefit for using executors? – damienix Nov 06 '12 at 11:01
  • @damienix They combine a queue and a thread pool and allow you to re-use thread, collect results/exception for individual tasks, cancel tasks, and shutdown a thread pool as a whole. – Peter Lawrey Nov 06 '12 at 11:05
  • Adding to Peter's points, the thread pool is flexible and configurable in the way it starts and stops threads. As of Java 5 `Thread` is considered as a low-level class only. – Marko Topolnik Nov 06 '12 at 11:21
  • And btw there is no `ExecutorServices.hutdownAndAwaitTermination()`, you'd probably use `pool.shutdown(); pool.awaitTermination(long, TimeUnit);` – damienix Nov 06 '12 at 11:46
  • Yes; it's in the Javadoc, but as an example of such a client method. It should have been `shutdownAndAwaitTermination(pool)`. I replaced with a simple two-liner for clarity. – Marko Topolnik Nov 06 '12 at 11:48
2

My solution is

Function:

public void runParallel(Runnable... runnables) throws InterruptedException {

List<Thread> threads = new ArrayList<Thread>(runnables.length);

for (Runnable runnable :runnables) {
    Thread th = new Thread(runnable);
    threads.add(th);
    th.start();
}

for (Thread th : threads) {
    th.join();
}

Use:

runParallel(new Runnable() {
                @Override
                public void run() {
                    method1()
                }
            }, new Runnable() {
                @Override
                public void run() {
                    method2()
                }
            }
);

any better ideas? Maybe there is a shorter way that I'm not aware of ;)

damienix
  • 6,463
  • 1
  • 23
  • 30
  • For future reference, it makes sense to edit an answer only to correct and improve the point it is already making; completely replacing original code with your own just means you are speaking through someone else's mouth, upvotes and downvotes going to the original answerer. BTW thanks for pointing out the error in my R class; corrected. – Marko Topolnik Nov 06 '12 at 11:31
  • I didn't really knew where I should place a code suggestion for you, comment it's a good place. I probably changed it too much as you noticed. Anyways, thanks for the answer. – damienix Nov 06 '12 at 11:44
  • The preferred (and even expected) way is to place the code you already have into your question, so the answerers have a clear starting point for their contributions. – Marko Topolnik Nov 06 '12 at 12:08
  • You're right. It was rightly a problem, because I expected from you to match not my question but answer that you hadn't had to read and it was mistake, sorry. Now i see it ;) – damienix Nov 06 '12 at 12:19
2

I prefer something like this:

public static void runParallel(Runnable... runnables) throws InterruptedException {
    final CountDownLatch done = new CountDownLatch(runnables.length);
    for (final Runnable r: runnables) {
        new Thread(new Runnable() {
             public void run() {
                 try {
                     r.run();
                 } finally {
                     done.countDown();
                 }
             }
        }).start();
    }
   done.await();
}

An advantage of this approach is that it also works with thread pool (i.e. you can replace new Thread(...).start() with executor.submit(...)).

Also it allows you to use pre-existing thread pool, unlike solutions based on awaitTermination() that force you to create new pools for each invocation.

axtavt
  • 239,438
  • 41
  • 511
  • 482
0

Following the API given by damienix:

public void runParallel(Runnable... runnables) throws InterruptedException {
    final ExecutorService pool = Executors.newFixedThreadPool(runnables.length);
    for (Runnable runnable: runnables) {
        pool.submit(runnable);
    }
    pool.shutdown();
    pool.awaitTermination(1, TimeUnit.MINUTES);
}
Tomasz Nurkiewicz
  • 334,321
  • 69
  • 703
  • 674