-1

I'm pretty new to Java multi threading, I've found a few responses for what I'm trying to do. However being new to java threading I'm still having a hard time following the responses.

Basically this is what I've got:

private final ExecutorService mFixedThreadPool;

public ThreadPool(int threadCount) {
    mFixedThreadPool = Executors.newFixedThreadPool(threadCount);
}

public interface Task {
    void phase1();
    void phase2();
    void phase3();
}

public void executeBatch(List<Runnable> tasks) {
    tasks.forEach(task -> mFixedThreadPool.execute(task::phase1));
    tasks.forEach(task -> mFixedThreadPool.execute(task::phase2));
    tasks.forEach(task -> mFixedThreadPool.execute(task::phase3));
    //only return on the main thread once all the tasks are complete.
    //(Dont destroy threadpool as the "executeBatch" method will be called in a loop)
}

I want to pause or stop or wait on the thread that calls "executeBatch" until the batch of work is complete. I know it's possible to do this using mFixedThreadPool.shutdown() then waiting till its shutdown successfully, however I would like to reuse the threads many times very often so shutting down each time is inefficient.

Hex Crown
  • 753
  • 9
  • 22
  • I don't understand. You've linked to an answer which literally tells you exactly what you need to do. What's the question here? – Michael Feb 07 '18 at 13:26
  • Possible duplicate of [How to wait for all tasks in an ThreadPoolExecutor to finish without shutting down the Executor?](https://stackoverflow.com/questions/3929361/how-to-wait-for-all-tasks-in-an-threadpoolexecutor-to-finish-without-shutting-do) – Michael Feb 07 '18 at 13:27
  • @Michael I just updated the code a bit, but basically I've read the response I linked to as well as the few others I could find for this specific question and I don't really get the point of the Futures collection or how I would go about implementing that answer. Like is the "myRunnable" the task, do I need to do that for every task, what is future.get(); supposed to do, etc. – Hex Crown Feb 07 '18 at 13:33
  • 1
    `myRunnable` is a [`Runnable`](https://docs.oracle.com/javase/9/docs/api/java/lang/Runnable.html), surprisingly enough. Just like your `task::phase`s are. A [future](https://docs.oracle.com/javase/9/docs/api/java/util/concurrent/Future.html) is the result of running a runnable. By iterating over all the futures, you're waiting until all submitted tasks have completed. Please read the JavaDocs for these classes and methods. They are easy to find. – Michael Feb 07 '18 at 13:40

2 Answers2

1

If what you want is a thread pool that doesn't start the next thread until the previous one has finished you can simply create a FixedThreadPool with one thread:

ExecutorService threadPool = Executors.newFixedThreadPool(1);

If what you want is sleep your current thread until the pool has finished using shutdown. shutdown() is meant precisely for this kind of task, but after shutdown you will need to create a new ExecutorService:

threadPool.shutdown();
try {
  threadPool.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
  ...
}

You could encapsulate your ExecutorService in an ExecutorCompletionService. This will notify you when it finishes without shutting down the Executor, like you want. See some info here.

One last option is using Future. The get() method blocks until that thread has finished so you could:

ExecutorService threadPool = Executors.newFixedThreadPool(4);
List<Callable<String>> tasks = new ArrayList<>();
List<Future<String>> futures = new ArrayList<>();
List<String> result = new ArrayList<>();
tasks.stream().forEachOrdered(task -> futures.add(threadPool.submit(task)));
for (Future<String> future :futures) {
    try {
        result.add(future.get());
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (ExecutionException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }   
}
Calabacin
  • 725
  • 2
  • 8
  • 19
  • I think my question is pretty clear, I want a thread pool that has n threads that I can queue up batches of tasks. While these tasks are executing in parallel, the main thread waits for all of the tasks to be complete. kinda like for (int i = 0; i < n; i++) { Queue up n tasks then execute all the tasks as quickly as possible (thread pool) and continue on the main loop} – Hex Crown Feb 07 '18 at 13:37
  • 1
    In that case I would use shutdown. It prevents that more tasks are added to the ExecutorService. If you don't want that, you could use the Future option, but you could have problems if more tasks are added later. – Calabacin Feb 07 '18 at 13:40
  • The task batches are quite well defined and won't be added while the queue is being processed, just before/after the quantity of items may increase or decrease between processing however. Would the possible problems you mention still pose a threat in this type of life cycle? – Hex Crown Feb 07 '18 at 13:52
  • I would still go for the shutdown solution with awaitTermination. It works in all cases and it is really simple to use. Another option is encasing your ExecutorService in an in an ExecutorCompletionService. – Calabacin Feb 07 '18 at 14:33
0

I think fork/join framework can give you what you want. You can control the execution and if needed unfork tasks and compute it in main thread.