2

I am using executor service for multi threading. Spanned across 15 threads, current process does completes 15 threads before moving on to next executor services which is again spanned across 15 threads. I am looking for code help where if any of current threads in step 1 executor services completes processing, i need to move on to next executor services which can start using the threads instead of waiting on completion of 15 threads in step 1 to complete.

I want to utilize the threads completed and move on to step 2 even if other threads are getting executed in step1 and as soon as each thread in step 1 gets completed, step 2 can grab and continue processing. Suggestions pls

// Step 1 
ExecutorService executor1 = Executors.newFixedThreadPool(15);
for (int i=0;i<=15;i++) { 
    Runnable worker = new Runnable("Step 1 Insert"); 
    executor1.execute(worker); } 
executor1.shutdown(); 
// Step 2 
ExecutorService executor2 = Executors.newFixedThreadPool(15);
for (int i=0;i<=15;i++) { 
    Runnable worker = new Runnable("Step 2 Insert"); 
    executor2.execute(worker); } 
executor2.shutdown();
Fildor
  • 14,510
  • 4
  • 35
  • 67
user3723562
  • 73
  • 1
  • 2
  • 15
  • // Step 1 ExecutorService executor1 = Executors.newFixedThreadPool(15) for (int i=0;i<=15;i++) { Runnable worker = new Runnable("Step 1 Insert"); executor1.execute(worker); } executor1.shutdown(); // Step 2 ExecutorService executor2 = Executors.newFixedThreadPool(15) for (int i=0;i<=15;i++) { Runnable worker = new Runnable("Step 2 Insert"); executor2.execute(worker); } executor2.shutdown(); – user3723562 Jan 25 '16 at 14:46
  • For automatism of thread recycling you should consider using the fork-join framework instead (available from Java 7). – Mena Jan 25 '16 at 14:50
  • 1
    Use a single executor instead of trying to make two executors to behave like a single executor. – Holger Jan 25 '16 at 14:55
  • I second Holger. How did you configure your Executor? You can just submit more Tasks and the free Threads will pick 'em up. Ah, you added code in comment ... didn't see that. Just submit a Step 2 Task within Step 1 right at the end and you're done. – Fildor Jan 25 '16 at 15:08
  • Please edit your question to show the code. Nobody likes seeing code pasted into a comment. – Solomon Slow Jan 25 '16 at 15:14
  • Q: Why shut down your first thread pool and then immediately create a new one?. The whole point of using a thread pool is to _re-use_ threads (creating and destroying threads is expensive). But, in your code example, no thread ever runs more than one task. Why don't you just use the same thread pool to execute the second batch of tasks? – Solomon Slow Jan 25 '16 at 15:17
  • @jameslarge I guess OP wanted to implement the "start step 2 after finishing step 1" requirement. Obviously with not much of a success. – Fildor Jan 25 '16 at 15:19
  • @Fildor, I guessed that, and was hoping OP himself/herself would answer. One way to wait for a group of tasks to complete would be to submit `Callable` tasks, and then call `future.get()` for each of the returned `Future` objects. Another way would be to have each of the tasks decrement a `CountDownLatch`, and then call `latch.await()`. – Solomon Slow Jan 25 '16 at 15:40
  • I understand op that he does not want to wait for the group. Just the individual task. – Fildor Jan 25 '16 at 16:01
  • Pass Executor2 to Runnable object. After completion of task in run method, add new task to Executor2. – Ravindra babu Jan 25 '16 at 16:04

4 Answers4

1

Why can't you just do all the steps in the same Runnable? e.g.

ExecutorService executor = Executors.newFixedThreadPool(15);
for (int i=0;i<=15;i++) { 
    Runnable worker = new Runnable() {
        public void run() {
            doStep1();
            doStep2();
            doStep3();
            ...
        }
    }; 
    executor.execute(worker);
}
executor.shutdown();
Tesseract
  • 8,049
  • 2
  • 20
  • 37
1

@SpiderPig's answer is one good solution IMHO, yet I would like to give an alternative in case you want to decouple steps:

Use one single Executor, in your case the requirement seems to be a FixedThreadPool with 15 Threads.

Next would be to define Step-Runnables like so:

class StepX implements Runnable{
    private final State _state; // Reference to the data to work on.
    StepX( State state ){
        _state = state;
    }

    public void run(){ 
        // work on _state
        executor.submit( new StepXplusOne( _state ) ); // reference executor in outer class and schedule next step.
    }
} 

You can see that I used a State object, which holds all data you need to perform the steps and collect the result. Of course you'd need to define StepX as Step1, Step2, ...

In the outer class, you'd only have to submit N Step1-Runnables and it will only use your 15 Threads and go through the steps.

I left out a means to signal when all steps are done, because there are plenty of possibilities to do this and I am sure you can pick one by yourself.

Fildor
  • 14,510
  • 4
  • 35
  • 67
0

You can use ExecutorCompletionService. I slightly modified example from JavaDoc

ExecutorService executor1 = Executors.newFixedThreadPool(15);
ExecutorService executor2 = Executors.newFixedThreadPool(15);

....

CompletionService<Result> ecs = new ExecutorCompletionService<Result>(executor1);
for (Callable<Result> s : solvers)
    ecs.submit(s);
int n = solvers.size();
for (int i = 0; i < n; ++i) {
    Result r = ecs.take().get();
    if (r != null)
        executor2.submit(r);
}
executor1.shutdown();
//and shutdown executor2 when you don't need it

Result class is just for example and I assume it implements Callable or Runnable so it could be submitted into the second executor.

You can also init instance of ExecutorService as new ThreadPoolExecutor(0, 15, 10, TimeUnit.SECONDS, new LinkedBlockingQueue()) to terminate threads which are not needed right now, but you want to reuse this executor later.

Or you can simply use one executor. After receiving a completed task from ExecutorCompletionService resubmit it (or its result) into the same executor (Thanks @Fildor). But in this case you need to determine when task is completed first time.

for (int i = 0; i < n;) {
    Result r = ecs.take().get();
    if (r != null && isCompletedFirstTime(r))//some user defined function
        executor1.submit(r);
    else 
        ++i;//we need to know when to stop, otherwise we'll stuck in `take()`
}
dezhik
  • 990
  • 10
  • 16
  • 1
    You do not need more than 1 Executor to implement the requirement. CompletionService is a good idea. But you do not need it neither to get what OP wants. – Fildor Jan 25 '16 at 15:25
  • You are right. But I don't know for sure what he needs because I don't know his task. So I try to give a more general solution. When you use two isolated executors as class variables and each time a function is called you need to run N tasks in first one and after that submit their results into another group of workers. So the first group will able to process new requests. – dezhik Jan 25 '16 at 15:31
  • I have actually have close to 20 executor services (20 steps) each of which working on 15 threads.. I just put an example of 2 services. I cannot have more than 15 threads running simultaneously. So process starts of with 15 threads in step 1 and say in 20 mins.. i am looking for 15 threads running with 1 thread in step 1 and 4 threads in step 2 and 5 threads in step 3 and 5 threads in step 4. – user3723562 Jan 25 '16 at 15:39
  • May be it's better to modify the code you submit into executor to run all these 20 step one by one? Or you can use updated solution (thanks one more time to @Fildor for pointing into it) where we resubmit tasks (or its result) into the same executor. But you need to define condition when to stop submitting it and when to increment number of fully finished jobs. In my example I did it for case when there are only two steps. – dezhik Jan 25 '16 at 16:04
  • Will try out this option. – user3723562 Jan 25 '16 at 17:35
-1

You can try use CountDownLatch class.

http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/CountDownLatch.html

    final CountDownLatch latch = new CountDownLatch(1);

    ExecutorService executor1 = Executors.newFixedThreadPool(15);
    for (int i = 0; i <= 15; i++) {
        Runnable worker = new Runnable() {

            @Override
            public void run() {
                latch.countDown();

            }
        };
        executor1.execute(worker);
    }

    latch.await();

    ExecutorService executor2 = Executors.newFixedThreadPool(15);
    for (int i = 0; i <= 15; i++) {
        Runnable worker = new Runnable("Step 2 Insert");
        executor2.execute(worker);
    }
    executor2.shutdown();
  • `new CountDownLatch(1);` means it must be decremented only once before it returns from `await();`. So this wouldn't help. This code will submit 15 runnables into executor2 right after one `latch.countDown();` occurs. – dezhik Jan 25 '16 at 15:33