Reputation: 153
I have a ThreadPoolExecutor with one thread that will be used for batch processing, So before assigning a new task to the executor i have to wait for the earlier task to complete, i was doing this by depending upon the value for active jobs, but seeing in detail i found that, the executor doesn't executes the task instantly.
The problem this is causing to me is that i am ready to give the next batch but the first task has not yet started thus the value of active jobs is 0.
How can i get to run the task instantly. I am also OK with any other executor or way that this can be done.
Upvotes: 1
Views: 2117
Reputation: 338775
Apparently you want to run multiple tasks immediately but in the order submitted.
Quite easy: Use an executor service backed by a single thread. The executor buffers up the tasks while waiting on earlier ones to complete. With on a single thread in the thread pool, only one task at a time can be executed, so they will be done sequentially in the order submitted.
The Executors
class provides a choice of a few different thread pools backing an executor service. You want Executors.newSingleThreadExecutor()
.
ExecutorService es = Executors.newSingleThreadExecutor() ;
Submit a series of Runnable
or Callable
objects. Each represents a task to be executed.
es.submit( ( ) -> System.out.println( "Hello. " + Instant.now() ) ) ;
es.submit( ( ) -> System.out.println( "Bonjour. " + Instant.now() ) ) ;
es.submit( ( ) -> System.out.println( "Aloha. " + Instant.now() ) ) ;
es.submit( ( ) -> System.out.println( "Ciào. " + Instant.now() ) ) ;
es.submit( ( ) -> System.out.println( "Shwmai. " + Instant.now() ) ) ;
Optionally, you can capture the Future
object returned by each call to submit
if you want to track completion of the tasks. (not shown in code above)
See this code run live at IdeOne.com.
Hello. 2019-11-29T09:10:13.426987Z
Bonjour. 2019-11-29T09:10:13.472719Z
Aloha. 2019-11-29T09:10:13.473177Z
Ciào. 2019-11-29T09:10:13.473479Z
Shwmai. 2019-11-29T09:10:13.473974Z
Upvotes: 0
Reputation: 3956
You should probably use submit
method from ExecutorService
to schedule your tasks. Here is a working program that uses single thread executor to run 10 tasks. I casted to ThreadPoolExecutor
to monitor thread pool state. You can wait for a single task by calling get
on its corresponding Future
instance or wait for all the tasks by invoking awaitTermination
. If you don't need result from the Future
just use Void
. Hope it helps.
public class Main {
static class TimingCallable implements Callable<Long> {
static int MIN_WAIT = 200;
@Override
public Long call() {
long start = System.currentTimeMillis();
try {
Thread.sleep(MIN_WAIT + new Random().nextInt(300));
} catch (InterruptedException e) {
//DO NOTHING
}
return System.currentTimeMillis() - start;
}
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService executor = Executors.newFixedThreadPool(1);
@SuppressWarnings("unchecked")
Future<Long>[] futureResults = new Future[10];
for(int i =0; i < futureResults.length; i++) {
futureResults[i] = executor.submit(new TimingCallable());
System.out.println(String.format("ActiveCount after submitting %d tasks: ", i+1) + ((ThreadPoolExecutor)executor).getActiveCount());
System.out.println(String.format("Queue size after submitting %d tasks: ", i+1) + ((ThreadPoolExecutor)executor).getQueue().size());
}
Thread.sleep(2000);
System.out.println("ActiveCount after 2 seconds: " + ((ThreadPoolExecutor)executor).getActiveCount());
System.out.println("Queue size after 2 seconds: " + ((ThreadPoolExecutor)executor).getQueue().size());
for(int i =0; i < futureResults.length; i++) {
if (futureResults[i].isDone()) {
System.out.println(String.format("%d task is done with execution time: ", i) + futureResults[i].get());
}
} //Waiting for the last task to finish
System.out.println("Waiting for the last task result: " + futureResults[9].get());
executor.shutdown();
executor.awaitTermination(10, TimeUnit.SECONDS);
}
}
Upvotes: 2
Reputation: 271
If you are having only one thread to execute just use LinkedQueue for storing jobs once thread is done with the execution then only it will pick another task.
ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1,1, TimeUnit.MINUTES, new LinkedBlockingQueue<Runnable>());
Also you can have different strategies if you restricting size
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html
Read Rejected tasks
Upvotes: 0