In my program, the user can trigger different tasks via an interface, which take some time to process. Therefore they are executed by threads. So far I have implemented it so that I have an executer with one thread that executes all tasks one after the other. But now I would like to parallelize everything a little bit.
i.e. I would like to run tasks in parallel, except if they have the same path, then I want to run them sequentially. For example, I have 10 threads in my pool and when a task comes in, the task should be assigned to the worker which is currently processing a task with the same path. If no task with the same path is currently being processed by a worker, then the task should be processed by a currently free worker.
Additional info: A task is any type of task that is executed on a file in the local file system. For example, renaming a file. Therefore, the task have the attribute path. And I don't want to execute two tasks on the same file at the same time, so such tasks with the same paths should be performed sequentially.
Here is my sample code but there is work to do:
One of my problems is, I need a safe way to check if a worker is currently running and get the path of the currently running worker. By safe I mean, that no problems of simultaneous access or other thread problems occur.
public class TasksOrderingExecutor {
public interface Task extends Runnable {
//Task code here
String getPath();
}
private static class Worker implements Runnable {
private final LinkedBlockingQueue<Task> tasks = new LinkedBlockingQueue<>();
//some variable or mechanic to give the actual path of the running tasks??
private volatile boolean stopped;
void schedule(Task task) {
tasks.add(task);
}
void stop() {
stopped = true;
}
#Override
public void run() {
while (!stopped) {
try {
Task task = tasks.take();
task.run();
} catch (InterruptedException ie) {
// perhaps, handle somehow
}
}
}
}
private final Worker[] workers;
private final ExecutorService executorService;
/**
* #param queuesNr nr of concurrent task queues
*/
public TasksOrderingExecutor(int queuesNr) {
Preconditions.checkArgument(queuesNr >= 1, "queuesNr >= 1");
executorService = new ThreadPoolExecutor(queuesNr, queuesNr, 0, TimeUnit.SECONDS, new SynchronousQueue<>());
workers = new Worker[queuesNr];
for (int i = 0; i < queuesNr; i++) {
Worker worker = new Worker();
executorService.submit(worker);
workers[i] = worker;
}
}
public void submit(Task task) {
Worker worker = getWorker(task);
worker.schedule(task);
}
public void stop() {
for (Worker w : workers) w.stop();
executorService.shutdown();
}
private Worker getWorker(Task task) {
//check here if a running worker with a specific path exists? If yes return it, else return a free worker. How do I check if a worker is currently running?
return workers[task.getPath() //HERE I NEED HELP//];
}
}
Seems like you have a pair of problems:
You want to check the status of tasks submitted to an executor service
You want to run tasks in parallel, and possibly prioritize them
Future
For the first problem, capture the Future object returned when you submit a task to an executor service. You can check the Future object for its completion status.
Future< Task > future = myExecutorService.submit( someTask ) ;
…
boolean isCancelled = future.isCancelled() ; // Returns true if this task was cancelled before it completed normally.
boolean isDone = future.isDone(); // Returns true if this task completed.
The Future is of a type, and that type can be your Task class itself. Calling Future::get yields the Task object. You can then interrogate that Task object for its contained file path.
Task task = future.get() ;
String path = task.getPath() ; // Access field via getter from your `Task` object.
Executors
Rather than instantiating new ThreadPoolExecutor, use the Executors utility class to instantiate an executor service on your behalf. Instantiating ThreadPoolExecutor directly is not needed for most common scenarios, as mentioned in the first line of its Javadoc.
ExecutorService es = Executors.newFixedThreadPool( 3 ) ; // Instantiate an executor service backed by a pool of three threads.
For the second problem, use an executor service backed by a thread pool rather than a single thread. The executor service automatically assigns the submitted task to an available thread.
As for grouping or prioritizing, use multiple executor services. You can instantiate more than one. You can have as many executor services as you want, provided you do not overload the demand on your deployment machine for CPU cores and memory (think about your maximum simultaneous usage).
ExecutorService esSingleThread = Executors.newSingleThreadExecutor() ;
ExecutorService esMultiThread = Executors.newCachedThreadPool() ;
One executor service might be backed by a single thread to limit the demands on the deployment computer, while others might be backed by a thread pool to get more work done. You can use these multiple executor services as your multiple queues. No need for you to be managing queues and workers as seen in the code of your Question. Executors were invented to further simplify working with multiple threads.
Concurrency
You said:
And I don't want to execute two tasks on the same file at the same time, so such tasks with the same paths should be performed sequentially.
You should have a better way to handle the concurrency conflict that just scheduling tasks on threads.
Java has ways to manage concurrent access to files. Search to learn more, as this has been covered on Stack Overflow already.
Perhaps I have not understood fully your needs, so do comment if I am off-base.
It seems that you need some sort of "Task Dispatcher" that executes or holds some tasks depending on some identifier (here the Path of the file the task is applied to).
You could use something like this :
public class Dispatcher<I> implements Runnable {
/**
* The executor used to execute the submitted task
*/
private final Executor executor;
/**
* Map of the pending tasks
*/
private final Map<I, Deque<Runnable>> pendingTasksById = new HashMap<>();
/**
* set containing the id that are currently executed
*/
private final Set<I> runningIds = new HashSet<>();
/**
* Action to be executed by the dispatcher
*/
private final BlockingDeque<Runnable> actionQueue = new LinkedBlockingDeque<>();
public Dispatcher(Executor executor) {
this.executor = executor;
}
/**
* Task in the same group will be executed sequentially (but not necessarily in the same thread)
* #param id the id of the group the task belong
* #param task the task to execute
*/
public void submitTask(I id, Runnable task) {
actionQueue.addLast(() -> {
if (canBeLaunchedDirectly(id)) {
executeTask(id, task);
} else {
addTaskToPendingTasks(id, task);
ifPossibleLaunchPendingTaskForId(id);
}
});
}
#Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
actionQueue.takeFirst().run();
} catch (InterruptedException e) {
Thread.currentThread().isInterrupted();
break;
}
}
}
private void addTaskToPendingTasks(I id, Runnable task) {
this.pendingTasksById.computeIfAbsent(id, i -> new LinkedList<>()).add(task);
}
/**
* #param id an id of a group
* #return true if a task of the group with the provided id is currently executed
*/
private boolean isRunning(I id) {
return runningIds.contains(id);
}
/**
* #param id an id of a group
* #return an optional containing the first pending task of the group,
* an empty optional if no such task is available
*/
private Optional<Runnable> getFirstPendingTask(I id) {
final Deque<Runnable> pendingTasks = pendingTasksById.get(id);
if (pendingTasks == null) {
return Optional.empty();
}
assert !pendingTasks.isEmpty();
final Runnable result = pendingTasks.removeFirst();
if (pendingTasks.isEmpty()) {
pendingTasksById.remove(id);
}
return Optional.of(result);
}
private boolean canBeLaunchedDirectly(I id) {
return !isRunning(id) && pendingTasksById.get(id) == null;
}
private void executeTask(I id, Runnable task) {
this.runningIds.add(id);
executor.execute(() -> {
try {
task.run();
} finally {
actionQueue.addLast(() -> {
runningIds.remove(id);
ifPossibleLaunchPendingTaskForId(id);
});
}
});
}
private void ifPossibleLaunchPendingTaskForId(I id) {
if (isRunning(id)) {
return;
}
getFirstPendingTask(id).ifPresent(r -> executeTask(id, r));
}
}
To use it, you need to launch it in a separated thread (or you can adapt it for a cleaner solution) like this :
final Dispatcher<Path> dispatcher = new Dispatcher<>(Executors.newCachedThreadPool());
new Thread(dispatcher).start();
dispatcher.submitTask(path, task1);
dispatcher.submitTask(path, task2);
This is basic example, you might need to keep the thread and even better wrap all of that in a class.
all you need is a hash map of actors, with file path as a key. Different actors would run in parallel, and concrete actor would handle tasks sequentially.
Your solution is wrong because Worker class uses blocking operation take but is executed in a limited thread pool, which may lead to a thread starvation (a kind of deadlock). Actors do not block when waiting for next message.
import org.df4j.core.dataflow.ClassicActor;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.*;
public class TasksOrderingExecutor {
public static class Task implements Runnable {
private final String path;
private final String task;
public Task(String path, String task) {
this.path = path;
this.task = task;
}
//Task code here
String getPath() {
return path;
}
#Override
public void run() {
System.out.println(path+"/"+task+" started");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
}
System.out.println(path+"/"+task+" stopped");
}
}
static class Worker extends ClassicActor<Task> {
#Override
protected void runAction(Task task) throws Throwable {
task.run();
}
}
private final ExecutorService executorService;
private final Map<String,Worker> workers = new HashMap<String,Worker>(){
#Override
public Worker get(Object key) {
return super.computeIfAbsent((String) key, (k) -> {
Worker res = new Worker();
res.setExecutor(executorService);
res.start();
return res;
});
}
};
/**
* #param queuesNr nr of concurrent task queues
*/
public TasksOrderingExecutor(int queuesNr) {
executorService = ForkJoinPool.commonPool();
}
public void submit(Task task) {
Worker worker = getWorker(task);
worker.onNext(task);
}
public void stop() throws InterruptedException {
for (Worker w : workers.values()) {
w.onComplete();
}
executorService.shutdown();
executorService.awaitTermination(10, TimeUnit.SECONDS);
}
private Worker getWorker(Task task) {
//check here if a runnig worker with a specific path exists? If yes return it, else return a free worker. How do I check if a worker is currently running?
return workers.get(task.getPath());
}
public static void main(String[] args) throws InterruptedException {
TasksOrderingExecutor orderingExecutor = new TasksOrderingExecutor(20);
orderingExecutor.submit(new Task("path1", "task1"));
orderingExecutor.submit(new Task("path1", "task2"));
orderingExecutor.submit(new Task("path2", "task1"));
orderingExecutor.submit(new Task("path3", "task1"));
orderingExecutor.submit(new Task("path2", "task2"));
orderingExecutor.stop();
}
}
The protocol of execution shows that tasks with te same key are executed sequentially and tasks with different keys are executed in parallel:
path3/task1 started
path2/task1 started
path1/task1 started
path3/task1 stopped
path2/task1 stopped
path1/task1 stopped
path2/task2 started
path1/task2 started
path2/task2 stopped
path1/task2 stopped
I used my own actor library DF4J, but any other actor library can be used.
Related
This question already has answers here:
ThreadPoolExecutor Block When its Queue Is Full?
(10 answers)
Closed 1 year ago.
I am trying to code a solution in which a single thread produces I/O-intensive tasks that can be performed in parallel. Each task have significant in-memory data. So I want to be able limit the number of tasks that are pending at a moment.
If I create ThreadPoolExecutor like this:
ThreadPoolExecutor executor = new ThreadPoolExecutor(numWorkerThreads, numWorkerThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(maxQueue));
Then the executor.submit(callable) throws RejectedExecutionException when the queue fills up and all the threads are already busy.
What can I do to make executor.submit(callable) block when the queue is full and all threads are busy?
EDIT:
I tried this:
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
And it somewhat achieves the effect that I want achieved but in an inelegant way (basically rejected threads are run in the calling thread, so this blocks the calling thread from submitting more).
EDIT: (5 years after asking the question)
To anyone reading this question and its answers, please don't take the accepted answer as one correct solution. Please read through all answers and comments.
I have done this same thing. The trick is to create a BlockingQueue where the offer() method is really a put(). (you can use whatever base BlockingQueue impl you want).
public class LimitedQueue<E> extends LinkedBlockingQueue<E>
{
public LimitedQueue(int maxSize)
{
super(maxSize);
}
#Override
public boolean offer(E e)
{
// turn offer() and add() into a blocking calls (unless interrupted)
try {
put(e);
return true;
} catch(InterruptedException ie) {
Thread.currentThread().interrupt();
}
return false;
}
}
Note that this only works for thread pool where corePoolSize==maxPoolSize so be careful there (see comments).
The currently accepted answer has a potentially significant problem - it changes the behavior of ThreadPoolExecutor.execute such that if you have a corePoolSize < maxPoolSize, the ThreadPoolExecutor logic will never add additional workers beyond the core.
From ThreadPoolExecutor.execute(Runnable):
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
Specifically, that last 'else' block willl never be hit.
A better alternative is to do something similar to what OP is already doing - use a RejectedExecutionHandler to do the same put logic:
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
try {
if (!executor.isShutdown()) {
executor.getQueue().put(r);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RejectedExecutionException("Executor was interrupted while the task was waiting to put on work queue", e);
}
}
There are some things to watch out for with this approach, as pointed out in the comments (referring to this answer):
If corePoolSize==0, then there is a race condition where all threads in the pool may die before the task is visible
Using an implementation that wraps the queue tasks (not applicable to ThreadPoolExecutor) will result in issues unless the handler also wraps it the same way.
Keeping those gotchas in mind, this solution will work for most typical ThreadPoolExecutors, and will properly handle the case where corePoolSize < maxPoolSize.
Here is how I solved this on my end:
(note: this solution does block the thread that submits the Callable, so it prevents RejectedExecutionException from being thrown )
public class BoundedExecutor extends ThreadPoolExecutor{
private final Semaphore semaphore;
public BoundedExecutor(int bound) {
super(bound, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
semaphore = new Semaphore(bound);
}
/**Submits task to execution pool, but blocks while number of running threads
* has reached the bound limit
*/
public <T> Future<T> submitButBlockIfFull(final Callable<T> task) throws InterruptedException{
semaphore.acquire();
return submit(task);
}
#Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
semaphore.release();
}
}
How about using the CallerBlocksPolicy class if you are using spring-integration?
This class implements the RejectedExecutionHandler interface, which is a handler for tasks that cannot be executed by a ThreadPoolExecutor.
You can use this policy like this.
executor.setRejectedExecutionHandler(new CallerBlocksPolicy());
The main difference between CallerBlocksPolicy and CallerRunsPolicy is whether it blocks or runs the task in the caller thread.
Please refer to this code.
I know this is an old question but had a similar issue that creating new tasks was very fast and if there were too many an OutOfMemoryError occur because existing task were not completed fast enough.
In my case Callables are submitted and I need the result hence I need to store all the Futures returned by executor.submit(). My solution was to put the Futures into a BlockingQueue with a maximum size. Once that queue is full, no more tasks are generated until some are completed (elements removed from queue). In pseudo-code:
final ExecutorService executor = Executors.newFixedThreadPool(numWorkerThreads);
final LinkedBlockingQueue<Future> futures = new LinkedBlockingQueue<>(maxQueueSize);
try {
Thread taskGenerator = new Thread() {
#Override
public void run() {
while (reader.hasNext) {
Callable task = generateTask(reader.next());
Future future = executor.submit(task);
try {
// if queue is full blocks until a task
// is completed and hence no future tasks are submitted.
futures.put(future);
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
executor.shutdown();
}
}
taskGenerator.start();
// read from queue as long as task are being generated
// or while Queue has elements in it
while (taskGenerator.isAlive()
|| !futures.isEmpty()) {
Future future = futures.take();
// do something
}
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
} catch (ExecutionException ex) {
throw new MyException(ex);
} finally {
executor.shutdownNow();
}
I had the similar problem and I implemented that by using beforeExecute/afterExecute hooks from ThreadPoolExecutor:
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* Blocks current task execution if there is not enough resources for it.
* Maximum task count usage controlled by maxTaskCount property.
*/
public class BlockingThreadPoolExecutor extends ThreadPoolExecutor {
private final ReentrantLock taskLock = new ReentrantLock();
private final Condition unpaused = taskLock.newCondition();
private final int maxTaskCount;
private volatile int currentTaskCount;
public BlockingThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
long keepAliveTime, TimeUnit unit,
BlockingQueue<Runnable> workQueue, int maxTaskCount) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
this.maxTaskCount = maxTaskCount;
}
/**
* Executes task if there is enough system resources for it. Otherwise
* waits.
*/
#Override
protected void beforeExecute(Thread t, Runnable r) {
super.beforeExecute(t, r);
taskLock.lock();
try {
// Spin while we will not have enough capacity for this job
while (maxTaskCount < currentTaskCount) {
try {
unpaused.await();
} catch (InterruptedException e) {
t.interrupt();
}
}
currentTaskCount++;
} finally {
taskLock.unlock();
}
}
/**
* Signalling that one more task is welcome
*/
#Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
taskLock.lock();
try {
currentTaskCount--;
unpaused.signalAll();
} finally {
taskLock.unlock();
}
}
}
This should be good enough for you. Btw, original implementation was task size based because one task could be larger 100 time than another and submitting two huge tasks was killing the box, but running one big and plenty of small was Okay. If your I/O-intensive tasks are roughly the same size you could use this class, otherwise just let me know and I'll post size based implementation.
P.S. You would want to check ThreadPoolExecutor javadoc. It's really nice user guide from Doug Lea about how it could be easily customized.
I have implemented a solution following the decorator pattern and using a semaphore to control the number of executed tasks. You can use it with any Executor and:
Specify the maximum of ongoing tasks
Specify the maximum timeout to wait for a task execution permit (if the timeout passes and no permit is acquired, a RejectedExecutionException is thrown)
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import java.time.Duration;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.Semaphore;
import javax.annotation.Nonnull;
public class BlockingOnFullQueueExecutorDecorator implements Executor {
private static final class PermitReleasingDecorator implements Runnable {
#Nonnull
private final Runnable delegate;
#Nonnull
private final Semaphore semaphore;
private PermitReleasingDecorator(#Nonnull final Runnable task, #Nonnull final Semaphore semaphoreToRelease) {
this.delegate = task;
this.semaphore = semaphoreToRelease;
}
#Override
public void run() {
try {
this.delegate.run();
}
finally {
// however execution goes, release permit for next task
this.semaphore.release();
}
}
#Override
public final String toString() {
return String.format("%s[delegate='%s']", getClass().getSimpleName(), this.delegate);
}
}
#Nonnull
private final Semaphore taskLimit;
#Nonnull
private final Duration timeout;
#Nonnull
private final Executor delegate;
public BlockingOnFullQueueExecutorDecorator(#Nonnull final Executor executor, final int maximumTaskNumber, #Nonnull final Duration maximumTimeout) {
this.delegate = Objects.requireNonNull(executor, "'executor' must not be null");
if (maximumTaskNumber < 1) {
throw new IllegalArgumentException(String.format("At least one task must be permitted, not '%d'", maximumTaskNumber));
}
this.timeout = Objects.requireNonNull(maximumTimeout, "'maximumTimeout' must not be null");
if (this.timeout.isNegative()) {
throw new IllegalArgumentException("'maximumTimeout' must not be negative");
}
this.taskLimit = new Semaphore(maximumTaskNumber);
}
#Override
public final void execute(final Runnable command) {
Objects.requireNonNull(command, "'command' must not be null");
try {
// attempt to acquire permit for task execution
if (!this.taskLimit.tryAcquire(this.timeout.toMillis(), MILLISECONDS)) {
throw new RejectedExecutionException(String.format("Executor '%s' busy", this.delegate));
}
}
catch (final InterruptedException e) {
// restore interrupt status
Thread.currentThread().interrupt();
throw new IllegalStateException(e);
}
this.delegate.execute(new PermitReleasingDecorator(command, this.taskLimit));
}
#Override
public final String toString() {
return String.format("%s[availablePermits='%s',timeout='%s',delegate='%s']", getClass().getSimpleName(), this.taskLimit.availablePermits(),
this.timeout, this.delegate);
}
}
I think it is as simple as using a ArrayBlockingQueue instead of a a LinkedBlockingQueue.
Ignore me... that's totally wrong. ThreadPoolExecutor calls Queue#offer not put which would have the effect you require.
You could extend ThreadPoolExecutor and provide an implementation of execute(Runnable) that calls put in place of offer.
That doesn't seem like a completely satisfactory answer I'm afraid.
the cacheThreadPool automatically deletes threads if they are inactive for 60 seconds, as far as I know. Only what exactly that means inactive is not clear to me.
My implementation looks like this:
public class ProcessHandler {
private class Worker implements Runnable {
private final LinkedBlockingQueue<MyTask> tasks = new LinkedBlockingQueue<>();
void schedule(List<MyTask> task) {
tasks.addAll(task);
}
#Override
public void run() {
while (true) {
try {
var task = tasks.take();
task.run();
} catch (InterruptedException ie) {
// perhaps, handle somehow
}
}
}
}
private ExecutorService esMultiThread = Executors.newCachedThreadPool();
public void submitProcess(List<MyTask> task){
Worker test = new Worker();
test.schedule(task);
esMultiThread.execute(test);
}
}
I create a Instance of ProcessHandler and then I want to submit task over and over again with submitProcess. Every new call of submitProcess should start a new thread so that everything is processed in parallel, e.g. if I call submitProcess 10 times fast in a row. These tasks should then be processed by a new Thread from the cachedThreadPool.
My question now, while the worker is sleeping, i.e. waiting by take(), will the thread be killed if the worker gets nothing for more than 60 seconds, or does the thread live infinitely because "sleeping" is a state which is not considered inactive by the cacheThreadPool?
I am currently building an application that polls some data over a Wireless Sensor Network and process them afterwards to extract the necessary information.
I use an ExecutorService to run the polling Task multiple times (as many as the nodes in the network).
There will be a status Label in the GUI that will print the statuses of the ExecutorService. The statuses will be:
Polling node 1 (2, 3, 4, n)...
Terminating threads...
Polling completed
I post a snippet of the ExecutorServicecode below.
My problem is that "Polling finished" is printed in every single thread that is being stopped and not at the end; while ExecutorService is being shutting down. This is obvious, since every thread runs in parallel with the others.
Please correct me if I am wrong.
threadPool.shutdown();
executes as soon as all the running threads have been finished.
I have to find a way to check/listen to the current state of the ExecutorService and when enters the shutdown state to print the status label.
Any advise would be highly appreciated.
public class ScannerThread extends Thread {
...
private static final int NUM_OF_THREADS = Nodes.COUNT;
private static final int UPDATE_INTERVAL = 200;
private ExecutorService threadPool;
public ScannerThread() {
threadPool = Executors.newFixedThreadPool(NUM_OF_THREADS);
...
setDaemon(true);
}
#Override
public void run() {
// poll data from each node in parallel, in a separate thread
for (Node node : Nodes.COUNT) {
...
PollingTask task = new PollingTask(node.getID());
threadPool. execute(task);
}
// request shutdown of the thread pool
threadPool.shutdown();
try {
// wait for all threads that are currently running
while (!threadPool.awaitTermination(UPDATE_INTERVAL, MILLISECONDS)) {
statusLabel.setText("Terminating threads...");
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// polling completed
statusLabel.setText("Polling completed");
}
class PollingTask implements Runnable {
...
private String noteID;
PollingTask(String id) {
noteID = id;
...
}
#Override
public void run() {
...
}
}
}
i am trying to schedule bunch of tasks to execute periodically. under certain situations some task need to be stopped from scheduling, so i remove them from the interal queue of threadPoolExecutor. I do that from within the task itself
Below is my approach. I am not sure the idea of removing the task from the threadPoolExecutor service, from inside of the task can cause any problem.(look at the synchronized method name 'removeTask'. Is there a better way to accomplish what i am trying to do here.
public class SchedulerDaemon {
private ScheduledExecutorService taskScheduler;
private ScheduledFuture taskResult1, taskResult2;
private Task1 task1;
private Task2 task2;
public SchedulerDaemon(Task1 task, Task2 task2)
{
this.task1 = task1;
this.task2 = task2;1
taskScheduler = new ScheduledThreadPoolExecutor(1);
}
public void start() {
if(taskScheduler == null) {
taskScheduler = new ScheduledThreadPoolExecutor(1);
taskResult = taskScheduler.scheduleAtFixedRate(new TaskWrapper(task1) , 60000,60000, TimeUnit.MILLISECONDS);
taskResult2 = taskScheduler.scheduleAtFixedRate(new TaskWrapper(task2) , 60000,60000, TimeUnit.MILLISECONDS);
}
}
public void stop() {
if(taskScheduler != null) {
taskScheduler.shutdown();
taskResult1.cancel(false);
taskResult2.cancel(false);
taskScheduler = null;
taskResult = null;
}
}
public synchronized void removeTask( TaskWrapper task){
((ScheduledThreadPoolExecutor) taskScheduler).remove(task);
}
class TaskWrapper implements Runnable {
private Task myTask;
public TaskWrapper(Task task) {
myTask = task;
}
#Override
public void run() {
try {
boolean keepRunningTask = myTask.call();
if(!keepRunningTask) {
***//Should this cause any problem??***
removeTask(this);
}
} catch (Exception e) {
//the task threw an exception remove it from execution queue
***//Should this cause any problem??***
removeTask(this);
}
}
}
}
public Task1 implements Callable<Boolean> {
public Boolean call() {
if(<something>)
return true;
else
return false;
}
}
public Task2 implements Callable<Boolean> {
public Boolean call() {
if(<something>)
return true;
else
return false;
}
}
Whenever you schedule a task
ScheduledFuture<?> future = schedulerService.scheduleAtFixedRate(new AnyTask());
Future Object is returned.
Use this Future Object to cancel this Task.
try this
future.cancel(true);
from JavaDocs
/**
* Attempts to cancel execution of this task. This attempt will
* fail if the task has already completed, has already been cancelled,
* or could not be cancelled for some other reason. If successful,
* and this task has not started when <tt>cancel</tt> is called,
* this task should never run. If the task has already started,
* then the <tt>mayInterruptIfRunning</tt> parameter determines
* whether the thread executing this task should be interrupted in
* an attempt to stop the task.
*
* <p>After this method returns, subsequent calls to {#link #isDone} will
* always return <tt>true</tt>. Subsequent calls to {#link #isCancelled}
* will always return <tt>true</tt> if this method returned <tt>true</tt>.
*
* #param mayInterruptIfRunning <tt>true</tt> if the thread executing this
* task should be interrupted; otherwise, in-progress tasks are allowed
* to complete
* #return <tt>false</tt> if the task could not be cancelled,
* typically because it has already completed normally;
* <tt>true</tt> otherwise
*/
Canceling a task by force is dangerous, that is why stop is mark to remove from java, so,
in alternative you should have a shared flag in your thread...
something like: can i live? can i live? no? ok return! this seam hugely but is the safe way!
I am trying to execute lots of tasks using a ThreadPoolExecutor. Below is a hypothetical example:
def workQueue = new ArrayBlockingQueue<Runnable>(3, false)
def threadPoolExecutor = new ThreadPoolExecutor(3, 3, 1L, TimeUnit.HOURS, workQueue)
for(int i = 0; i < 100000; i++)
threadPoolExecutor.execute(runnable)
The problem is that I quickly get a java.util.concurrent.RejectedExecutionException since the number of tasks exceeds the size of the work queue. However, the desired behavior I am looking for is to have the main thread block until there is room in the queue. What is the best way to accomplish this?
In some very narrow circumstances, you can implement a java.util.concurrent.RejectedExecutionHandler that does what you need.
RejectedExecutionHandler block = new RejectedExecutionHandler() {
rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
executor.getQueue().put( r );
}
};
ThreadPoolExecutor pool = new ...
pool.setRejectedExecutionHandler(block);
Now. This is a very bad idea for the following reasons
It's prone to deadlock because all the threads in the pool may die before the thing you put in the queue is visible. Mitigate this by setting a reasonable keep alive time.
The task is not wrapped the way your Executor may expect. Lots of executor implementations wrap their tasks in some sort of tracking object before execution. Look at the source of yours.
Adding via getQueue() is strongly discouraged by the API, and may be prohibited at some point.
A almost-always-better strategy is to install ThreadPoolExecutor.CallerRunsPolicy which will throttle your app by running the task on the thread which is calling execute().
However, sometimes a blocking strategy, with all its inherent risks, is really what you want. I'd say under these conditions
You only have one thread calling execute()
You have to (or want to) have a very small queue length
You absolutely need to limit the number of threads running this work (usually for external reasons), and a caller-runs strategy would break that.
Your tasks are of unpredictable size, so caller-runs could introduce starvation if the pool was momentarily busy with 4 short tasks and your one thread calling execute got stuck with a big one.
So, as I say. It's rarely needed and can be dangerous, but there you go.
Good Luck.
What you need to do is to wrap your ThreadPoolExecutor into Executor which explicitly limits amount of concurrently executed operations inside it:
private static class BlockingExecutor implements Executor {
final Semaphore semaphore;
final Executor delegate;
private BlockingExecutor(final int concurrentTasksLimit, final Executor delegate) {
semaphore = new Semaphore(concurrentTasksLimit);
this.delegate = delegate;
}
#Override
public void execute(final Runnable command) {
try {
semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
return;
}
final Runnable wrapped = () -> {
try {
command.run();
} finally {
semaphore.release();
}
};
delegate.execute(wrapped);
}
}
You can adjust concurrentTasksLimit to the threadPoolSize + queueSize of your delegate executor and it will pretty much solve your problem
You could use a semaphore to block threads from going into the pool.
ExecutorService service = new ThreadPoolExecutor(
3,
3,
1,
TimeUnit.HOURS,
new ArrayBlockingQueue<>(6, false)
);
Semaphore lock = new Semaphore(6); // equal to queue capacity
for (int i = 0; i < 100000; i++ ) {
try {
lock.acquire();
service.submit(() -> {
try {
task.run();
} finally {
lock.release();
}
});
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
Some gotchas:
Only use this pattern with a fixed thread pool. The queue is unlikely to be full often, thus new threads won't be created. Check out the java docs on ThreadPoolExecutor for more details: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ThreadPoolExecutor.html There is a way around this, but it is out of scope of this answer.
Queue size should be higher than the number of core threads. If we were to make the queue size 3, what would end up happening is:
T0: all three threads are doing work, the queue is empty, no permits are available.
T1: Thread 1 finishes, releases a permit.
T2: Thread 1 polls the queue for new work, finds none, and waits.
T3: Main thread submits work into the pool, thread 1 starts work.
The example above translates to thread the main thread blocking thread 1. It may seem like a small period, but now multiply the frequency by days and months. All of a sudden, short periods of time add up to a large amount of time wasted.
This is what I ended up doing:
int NUM_THREADS = 6;
Semaphore lock = new Semaphore(NUM_THREADS);
ExecutorService pool = Executors.newCachedThreadPool();
for (int i = 0; i < 100000; i++) {
try {
lock.acquire();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
pool.execute(() -> {
try {
// Task logic
} finally {
lock.release();
}
});
}
A fairly straightforward option is to wrap your BlockingQueue with an implementation that calls put(..) when offer(..) is being invoked:
public class BlockOnOfferAdapter<T> implements BlockingQueue<T> {
(..)
public boolean offer(E o) {
try {
delegate.put(o);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return false;
}
return true;
}
(.. implement all other methods simply by delegating ..)
}
This works because by default put(..) waits until there is capacity in the queue when it is full, see:
/**
* Inserts the specified element into this queue, waiting if necessary
* for space to become available.
*
* #param e the element to add
* #throws InterruptedException if interrupted while waiting
* #throws ClassCastException if the class of the specified element
* prevents it from being added to this queue
* #throws NullPointerException if the specified element is null
* #throws IllegalArgumentException if some property of the specified
* element prevents it from being added to this queue
*/
void put(E e) throws InterruptedException;
No catching of RejectedExecutionException or complicated locking necessary.
Here is my code snippet in this case:
public void executeBlocking( Runnable command ) {
if ( threadPool == null ) {
logger.error( "Thread pool '{}' not initialized.", threadPoolName );
return;
}
ThreadPool threadPoolMonitor = this;
boolean accepted = false;
do {
try {
threadPool.execute( new Runnable() {
#Override
public void run() {
try {
command.run();
}
// to make sure that the monitor is freed on exit
finally {
// Notify all the threads waiting for the resource, if any.
synchronized ( threadPoolMonitor ) {
threadPoolMonitor.notifyAll();
}
}
}
} );
accepted = true;
}
catch ( RejectedExecutionException e ) {
// Thread pool is full
try {
// Block until one of the threads finishes its job and exits.
synchronized ( threadPoolMonitor ) {
threadPoolMonitor.wait();
}
}
catch ( InterruptedException ignored ) {
// return immediately
break;
}
}
} while ( !accepted );
}
threadPool is a local instance of java.util.concurrent.ExecutorService which has been initialized already.
I solved this problem using a custom RejectedExecutionHandler, which simply blocks the calling thread for a little while and then tries to submit the task again:
public class BlockWhenQueueFull implements RejectedExecutionHandler {
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
// The pool is full. Wait, then try again.
try {
long waitMs = 250;
Thread.sleep(waitMs);
} catch (InterruptedException interruptedException) {}
executor.execute(r);
}
}
This class can just be used in the thread-pool executor as a RejectedExecutionHandler like any other. In this example:
executorPool = new def threadPoolExecutor = new ThreadPoolExecutor(3, 3, 1L, TimeUnit.HOURS, workQueue, new BlockWhenQueueFull())
The only downside I see is that the calling thread might get locked slightly longer than strictly necessary (up to 250ms). For many short-running tasks, perhaps decrease the wait-time to 10ms or so. Moreover, since this executor is effectively being called recursively, very long waits for a thread to become available (hours) might result in a stack overflow.
Nevertheless, I personally like this method. It's compact, easy to understand, and works well. Am I missing anything important?
Ok, old thread but this is what I found when searching for blocking thread executor. My code tries to get a semaphore when the task is submitted to the task queue. This blocks if there are no semaphores left. As soon as a task is done the semaphore is released with the decorator. Scary part is that there is a possibility of losing semaphore but that could be solved with for example a timed job that just clears semaphores on a timed basis.
So here my solution:
class BlockingThreadPoolTaskExecutor(concurrency: Int) : ThreadPoolTaskExecutor() {
companion object {
lateinit var semaphore: Semaphore
}
init {
semaphore = Semaphore(concurrency)
val semaphoreTaskDecorator = SemaphoreTaskDecorator()
this.setTaskDecorator(semaphoreTaskDecorator)
}
override fun <T> submit(task: Callable<T>): Future<T> {
log.debug("submit")
semaphore.acquire()
return super.submit(task)
}
}
private class SemaphoreTaskDecorator : TaskDecorator {
override fun decorate(runnable: Runnable): Runnable {
log.debug("decorate")
return Runnable {
try {
runnable.run()
} finally {
log.debug("decorate done")
semaphore.release()
}
}
}
}
One could overwrite ThreadPoolExecutor.execute(command) to use a Semaphore, e.g.:
/**
* The setup answering the question needs to have:
*
* permits = 3
* corePoolSize = permits (i.e. 3)
* maximumPoolSize = corePoolSize (i.e. 3)
* workQueue = anything different to null
*
* With this setup workQueue won’t actually be used but only
* to check if it’s empty, which should always be the case.
* Any more than permits as value for maximumPoolSize will have
* no effect because at any moment no more than permits calls to
* super.execute() will be allowed by the semaphore.
*/
public class ExecutionBlockingThreadPool extends ThreadPoolExecutor {
private final Semaphore semaphore;
// constructor setting super(…) parameters and initializing semaphore
//
// Below is a bare minimum constructor; using
// corePoolSize = maximumPoolSize = permits
// allows one to use SynchronousQueue because I expect
// none other that isEmpty() to be called on it; it also
// allows for using 0L SECONDS because no more than
// corePoolSize threads should be attempted to create.
public ExecutionBlockingThreadPool(int corePoolSize) {
super(corePoolSize, corePoolSize, 0L, SECONDS, new SynchronousQueue<Runnable>());
semaphore = new Semaphore(corePoolSize, true);
}
public void execute(Runnable command) {
semaphore.acquire();
super.execute(() -> {
try {
command.run();
} finally {
semaphore.release();
}
}
}
}
You can imlement RejectedTaskHandler and get all the rejected tasks when Queue size if full. By default executors have the Abort policy so you can add these task back to the queue from handler or whatever the choice is.
public class ExecutorRejectedTaskHandlerFixedThreadPool {
public static void main(String[] args) throws InterruptedException {
//maximum queue size : 2
BlockingQueue<Runnable> blockingQueue =
new LinkedBlockingQueue<Runnable>(2);
CustomThreadPoolExecutor executor =
new CustomThreadPoolExecutor(4, 5, 5, TimeUnit.SECONDS,
blockingQueue);
RejectedTaskHandler rejectedHandler = new RejectedTaskHandler();
executor.setRejectedExecutionHandler(rejectedHandler);
//submit 20 the tasks for execution
//Note: only 7 tasks(5-max pool size + 2-queue size) will be executed and rest will be rejected as queue will be overflowed
for (int i = 0; i < 20; i++) {
executor.execute(new Task());
}
System.out.println("Thread name " + Thread.currentThread().getName());
}
static class Task implements Runnable {
#Override
public void run() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Thread - " + Thread.currentThread().getName() + " performing it's job");
}
}
static class RejectedTaskHandler implements RejectedExecutionHandler {
#Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.out.println("Task rejected" + r.toString());
}
}
public static class CustomThreadPoolExecutor extends ThreadPoolExecutor {
public CustomThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
long keepAliveTime, TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
#Override
protected void beforeExecute(Thread t, Runnable r) {
super.beforeExecute(t, r);
}
#Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
}
}
}