How to stop all tasks in the pool except last one? - java

I have a fixed pool with a single thread. When I submit new task I want to stop all old threads except last one.
private class MyPool extends ThreadPoolExecutor {
public MyPool(long keepAliveTime, TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
super(1, 1, keepAliveTime, unit, workQueue);
}
public boolean isReady() {
return semaphore;
}
#Override
public <T> Future<T> submit(Callable<T> task) {
// Iterate all existed task and stop
Future<T> future = super.submit(task);
return future;
}
private volatile boolean semaphore;
}
Code of running task:
private class MyTask implements Runnable {
private volatile boolean isRun = true;
private int id;
public MyTask(int id) {
this.id = id;
}
public void stop() {
isRun = false;
}
#Override
public void run() {
try {
System.out.println("Start " + id);
if (isRun) {
Thread.sleep(1000);
System.out.println("Stop " + id);
}
} catch(Exception e) {
e.printStackTrace();
}
}
}
I created my own class, but It doesn't correctly work because semaphore effects on a new task as well. What is the best way to do it?

This ThreadPoolExecutor kills the running thread if a new Callable is submitted:
class MyPool extends ThreadPoolExecutor {
private volatile Thread activeThread = null;
private static final Field FutureTask$runner;
static {
try {
FutureTask$runner = FutureTask.class.getDeclaredField("runner");
FutureTask$runner.setAccessible(true);
} catch (NoSuchFieldException e) {
throw new Error(e);
}
}
private static Thread getThread(FutureTask<?> task) {
try {
return (Thread) FutureTask$runner.get(task);
} catch (IllegalAccessException e) {
throw new Error(e);
}
}
public MyPool() {
super(1, 1,
//whatever here
5000, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>());
}
#Override
public <T> Future<T> submit(Callable<T> task) {
if(activeThread != null) {
activeThread.stop(); //kill
}
FutureTask<T> activeTask = (FutureTask<T>)super.submit(task);
activeThread = getThread(activeTask); //steal thread reference for killing
return activeTask;
}
}

Related

Is it possible to make a ThreadPoolExecutor with a PriorityBlockingQueue<Callable<Object>> queue?

I have tried to write a code for an assignment that I have. In that assignment I need to create a callable and to put it in a threadpool with a priority. I didnt succeed because I am unable to put a callable<Object> queue in the ThreadPoolExecutor queue section.
Here is the customExecuter code which uses ThreadPoolExecuter. the queue part in the new ThreadPoolExecuter is marked in red.
package Ex2Part2;
import java.util.concurrent.*;
public class CustomExecutor {
private final int minPoolSize;
private final int maxPoolSize;
private final PriorityBlockingQueue<Callable<Object>> queue;
private final ThreadPoolExecutor executor;
private int maxPriority = 0;
private boolean isShutdown = false;
public CustomExecutor() {
int availableProcessors = Runtime.getRuntime().availableProcessors();
this.minPoolSize = availableProcessors / 2;
this.maxPoolSize = availableProcessors - 1;
this.queue = new PriorityBlockingQueue<>();
this.executor = new ThreadPoolExecutor(minPoolSize, maxPoolSize, 0, TimeUnit.MILLISECONDS, queue);
}
public <T> CompletableFuture<T> submit(Callable<T> task, TaskType priority) throws Exception {
if (isShutdown) {
throw new IllegalStateException("Thread pool has already been shut down");
}
CompletableFuture<T> future = new CompletableFuture<>();
Task callable = new Task(task, priority);
future=callable.call();
maxPriority = Math.max(maxPriority, priority.getPriorityValue());
queue.put(callable);
return future;
}
public int getCurrentMax() {
return maxPriority;
}
public void gracefullyTerminate() {
isShutdown = true;
executor.shutdown();
try {
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
// Handle interrupted exception
}
}
}
Here is my task code:
public class Task implements Callable<Object> {
private Callable<?> task;
private TaskType priority;
public Task(Callable<?> task, TaskType priority) {
this.task = task;
this.priority = priority;
}
public static <T> Task createTask(Callable<T> task,TaskType priority)
{
Task newTask=new Task(task,priority);
return newTask;
}
#Override
public Object call() throws Exception {
return task.call();
}
public int Comperator(Task other) {
return Integer.compare(priority.getPriorityValue(), other.priority.getPriorityValue());
}
}
Another question that I have is in the CustomExecuter in the submit part I dont know how to return the future part so that I will be able to get it in my tests.
......................

Why does the ThreadpoolExecutor code never stop running?

I run the code in IntelliJ IDEA and it would not stop. I use exec.shutdownNow() instead and it stops successfully. So, I think is the problem of generator, but I can't figure out what problem it is.
The main method:
public static void main(String[] args) {
PrimeProducer generator = new PrimeProducer(new ArrayBlockingQueue<>(10));
ExecutorService exec = Executors.newFixedThreadPool(1);
exec.execute(generator);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
generator.cancel();
}
//generator.get();
exec.shutdown();
}
And the PrimeProducer class:
public class PrimeProducer extends Thread{
private final BlockingQueue<BigInteger> queue;
PrimeProducer(BlockingQueue<BigInteger> queue){
this.queue = queue;
}
#Override
public void run() {
try {
BigInteger p = BigInteger.ONE;
while(!Thread.currentThread().isInterrupted()){
queue.put(p = p.nextProbablePrime());
}
} catch (InterruptedException e) {
}
}
public void cancel(){interrupt();}
public void get(){
for(BigInteger i : queue){
System.out.println(i.toString());
}
}
}
The latest version that still can't work:
public class PrimeProducer implements Runnable {
private final BlockingQueue<BigInteger> queue;
PrimeProducer(BlockingQueue<BigInteger> queue){
this.queue = queue;
}
#Override
public void run() {
try {
BigInteger p = BigInteger.ONE;
while(!Thread.currentThread().isInterrupted()){
queue.put(p = p.nextProbablePrime());
}
} catch (InterruptedException e) {
}
}
public void cancel(){Thread.currentThread().interrupt();}
public synchronized void get(){
for(BigInteger i : queue){
System.out.println(i.toString());
}
}
}
You have PrimeProducer extend Thread, but you don't actually use it as a thread, you only use it as a Runnable, which is executed on a thread of the thread pool. The cancel has no effect, because it calls the interrupt() of a different thread than the one that is actually running. When you then call exec.shutdown(), the thread pool will interrupt its threads to signal them they should end, when then means PrimeProducer.run will stop.
Instead, use a volatile boolean to end your run (and implement Runnable instead of extending Thread):
public class PrimeProducer implements Runnable {
private final BlockingQueue<BigInteger> queue;
private volatile boolean cancelled;
PrimeProducer(BlockingQueue<BigInteger> queue) {
this.queue = queue;
}
#Override
public void run() {
try {
BigInteger p = BigInteger.ONE;
while (!cancelled) {
queue.put(p = p.nextProbablePrime());
}
} catch (InterruptedException e) {
}
}
public void cancel() {
cancelled = true;
}
public void get() {
for (BigInteger i : queue) {
System.out.println(i.toString());
}
}
}

ForkJoinPool resets thread interrupted state

I just noticed the following phenomena when cancelling a Future returned by ForkJoinPool. Given the following example code:
ForkJoinPool pool = new ForkJoinPool();
Future<?> fut = pool.submit(new Callable<Void>() {
#Override
public Void call() throws Exception {
while (true) {
if (Thread.currentThread().isInterrupted()) { // <-- never true
System.out.println("interrupted");
throw new InterruptedException();
}
}
}
});
Thread.sleep(1000);
System.out.println("cancel");
fut.cancel(true);
The program never prints interrupted. The docs of ForkJoinTask#cancel(boolean) say:
mayInterruptIfRunning - this value has no effect in the default implementation because interrupts are not used to control cancellation.
If ForkJoinTasks ignore interrupts, how else are you supposed to check for cancellation inside Callables submitted to a ForkJoinPool?
This happens because Future<?> is a ForkJoinTask.AdaptedCallable which extends ForkJoinTask, whose cancel method is:
public boolean cancel(boolean mayInterruptIfRunning) {
return setCompletion(CANCELLED) == CANCELLED;
}
private int setCompletion(int completion) {
for (int s;;) {
if ((s = status) < 0)
return s;
if (UNSAFE.compareAndSwapInt(this, statusOffset, s, completion)) {
if (s != 0)
synchronized (this) { notifyAll(); }
return completion;
}
}
}
It does not do any interruptions, it just sets status. I suppose this happens becouse ForkJoinPools's Futures might have a very complicated tree structure, and it is unclear in which order to cancel them.
Sharing some more light on top of #Mkhail answer:
Using ForkJoinPool execute() instead of submit() will force a failed Runnable to throw a worker exception, and this exception will be caught by the Thread UncaughtExceptionHandler.
Taking from Java 8 code:
submit is using AdaptedRunnableAction().
execute is using RunnableExecuteAction() (see the rethrow(ex)).
/**
* Adaptor for Runnables without results
*/
static final class AdaptedRunnableAction extends ForkJoinTask<Void>
implements RunnableFuture<Void> {
final Runnable runnable;
AdaptedRunnableAction(Runnable runnable) {
if (runnable == null) throw new NullPointerException();
this.runnable = runnable;
}
public final Void getRawResult() { return null; }
public final void setRawResult(Void v) { }
public final boolean exec() { runnable.run(); return true; }
public final void run() { invoke(); }
private static final long serialVersionUID = 5232453952276885070L;
}
/**
* Adaptor for Runnables in which failure forces worker exception
*/
static final class RunnableExecuteAction extends ForkJoinTask<Void> {
final Runnable runnable;
RunnableExecuteAction(Runnable runnable) {
if (runnable == null) throw new NullPointerException();
this.runnable = runnable;
}
public final Void getRawResult() { return null; }
public final void setRawResult(Void v) { }
public final boolean exec() { runnable.run(); return true; }
void internalPropagateException(Throwable ex) {
rethrow(ex); // rethrow outside exec() catches.
}
private static final long serialVersionUID = 5232453952276885070L;
}

How do I "cancel" a CountDownLatch?

I have multiple consumer threads waiting on a CountDownLatch of size 1 using await(). I have a single producer thread that calls countDown() when it successfully finishes.
This works great when there are no errors.
However, if the producer detects an error, I would like for it to be able to signal the error to the consumer threads. Ideally I could have the producer call something like abortCountDown() and have all of the consumers receive an InterruptedException or some other exception. I don't want to call countDown(), because this requires all of my consumer threads to then do an additional manual check for success after their call to await(). I'd rather they just receive an exception, which they already know how to handle.
I know that an abort facility is not available in CountDownLatch. Is there another synchronization primitive that I can easily adapt to effectively create a CountDownLatch that supports aborting the countdown?
JB Nizet had a great answer. I took his and polished it a little bit. The result is a subclass of CountDownLatch called AbortableCountDownLatch, which adds an "abort()" method to the class that will cause all threads waiting on the latch to receive an AbortException (a subclass of InterruptedException).
Also, unlike JB's class, the AbortableCountDownLatch will abort all blocking threads immediately on an abort, rather than waiting for the countdown to reach zero (for situations where you use a count>1).
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class AbortableCountDownLatch extends CountDownLatch {
protected boolean aborted = false;
public AbortableCountDownLatch(int count) {
super(count);
}
/**
* Unblocks all threads waiting on this latch and cause them to receive an
* AbortedException. If the latch has already counted all the way down,
* this method does nothing.
*/
public void abort() {
if( getCount()==0 )
return;
this.aborted = true;
while(getCount()>0)
countDown();
}
#Override
public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
final boolean rtrn = super.await(timeout,unit);
if (aborted)
throw new AbortedException();
return rtrn;
}
#Override
public void await() throws InterruptedException {
super.await();
if (aborted)
throw new AbortedException();
}
public static class AbortedException extends InterruptedException {
public AbortedException() {
}
public AbortedException(String detailMessage) {
super(detailMessage);
}
}
}
Encapsulate this behavior inside a specific, higher-level class, using the CountDownLatch internally:
public class MyLatch {
private CountDownLatch latch;
private boolean aborted;
...
// called by consumers
public void await() throws AbortedException {
latch.await();
if (aborted) {
throw new AbortedException();
}
}
// called by producer
public void abort() {
this.aborted = true;
latch.countDown();
}
// called by producer
public void succeed() {
latch.countDown();
}
}
You can create a wrapper around CountDownLatch that provides the ability to cancel the waiters. It will need to track the waiting threads and release them when they timeout as well as remember that the latch was cancelled so future calls to await will interrupt immediately.
public class CancellableCountDownLatch
{
final CountDownLatch latch;
final List<Thread> waiters;
boolean cancelled = false;
public CancellableCountDownLatch(int count) {
latch = new CountDownLatch(count);
waiters = new ArrayList<Thread>();
}
public void await() throws InterruptedException {
try {
addWaiter();
latch.await();
}
finally {
removeWaiter();
}
}
public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
try {
addWaiter();
return latch.await(timeout, unit);
}
finally {
removeWaiter();
}
}
private synchronized void addWaiter() throws InterruptedException {
if (cancelled) {
Thread.currentThread().interrupt();
throw new InterruptedException("Latch has already been cancelled");
}
waiters.add(Thread.currentThread());
}
private synchronized void removeWaiter() {
waiters.remove(Thread.currentThread());
}
public void countDown() {
latch.countDown();
}
public synchronized void cancel() {
if (!cancelled) {
cancelled = true;
for (Thread waiter : waiters) {
waiter.interrupt();
}
waiters.clear();
}
}
public long getCount() {
return latch.getCount();
}
#Override
public String toString() {
return latch.toString();
}
}
You could roll your own CountDownLatch out using a ReentrantLock that allows access to its protected getWaitingThreads method.
Example:
public class FailableCountDownLatch {
private static class ConditionReentrantLock extends ReentrantLock {
private static final long serialVersionUID = 2974195457854549498L;
#Override
public Collection<Thread> getWaitingThreads(Condition c) {
return super.getWaitingThreads(c);
}
}
private final ConditionReentrantLock lock = new ConditionReentrantLock();
private final Condition countIsZero = lock.newCondition();
private long count;
public FailableCountDownLatch(long count) {
this.count = count;
}
public void await() throws InterruptedException {
lock.lock();
try {
if (getCount() > 0) {
countIsZero.await();
}
} finally {
lock.unlock();
}
}
public boolean await(long time, TimeUnit unit) throws InterruptedException {
lock.lock();
try {
if (getCount() > 0) {
return countIsZero.await(time, unit);
}
} finally {
lock.unlock();
}
return true;
}
public long getCount() {
lock.lock();
try {
return count;
} finally {
lock.unlock();
}
}
public void countDown() {
lock.lock();
try {
if (count > 0) {
count--;
if (count == 0) {
countIsZero.signalAll();
}
}
} finally {
lock.unlock();
}
}
public void abortCountDown() {
lock.lock();
try {
for (Thread t : lock.getWaitingThreads(countIsZero)) {
t.interrupt();
}
} finally {
lock.unlock();
}
}
}
You may want to change this class to throw an InterruptedException on new calls to await after it has been cancelled. You could even have this class extend CountDownLatch if you needed that functionality.
Since Java 8 you can use CompletableFuture for this. One or more threads can call the blocking get() method:
CompletableFuture<Void> cf = new CompletableFuture<>();
try {
cf.get();
} catch (ExecutionException e) {
//act on error
}
another thread can either complete it successfully with cf.complete(null) or exceptionally with cf.completeExceptionally(new MyException())
There is a simple option here that wraps the CountDownLatch. It's similar to the second answer but does not have to call countdown repeatedly, which could be very expensive if the latch is for a large number. It uses an AtomicInteger for the real count, with a CountDownLatch of 1.
https://github.com/scottf/CancellableCountDownLatch/blob/main/CancellableCountDownLatch.java
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class CancellableCountDownLatch {
private final AtomicInteger count;
private final CountDownLatch cdl;
public CancellableCountDownLatch(int count) {
this.count = new AtomicInteger(count);
cdl = new CountDownLatch(1);
}
public void cancel() {
count.set(0);
cdl.countDown();
}
public void await() throws InterruptedException {
cdl.await();
}
public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
return cdl.await(timeout, unit);
}
public void countDown() {
if (count.decrementAndGet() <= 0) {
cdl.countDown();
}
}
public long getCount() {
return Math.max(count.get(), 0);
}
#Override
public String toString() {
return super.toString() + "[Count = " + getCount() + "]";
}
}

How to implement PriorityBlockingQueue with ThreadPoolExecutor and custom tasks

I've searched a lot but could not find a solutuion to my problem.
I have my own class, BaseTask, that uses a ThreadPoolExecutor to handle tasks. I want task prioritization, but when I try to use a PriorityBlockingQueue I get ClassCastException because the ThreadPoolExecutor wraps my Tasks into a FutureTask object.
This obviously makes sense because the FutureTask does not implement Comparable, but how would I go on to solve the priority problem? I've read that you could override newTaskFor() in ThreadPoolExecutor, but I can not seem to find this method at all...?
Any suggestions would be much appreciated!
Some code to help:
In my BaseTask class I have
private static final BlockingQueue<Runnable> sWorkQueue = new PriorityBlockingQueue<Runnable>();
private static final ThreadFactory sThreadFactory = new ThreadFactory() {
private final AtomicInteger mCount = new AtomicInteger(1);
public Thread newThread(Runnable r) {
return new Thread(r, "AsyncTask #" + mCount.getAndIncrement());
}
};
private static final BaseThreadPoolExecutor sExecutor = new BaseThreadPoolExecutor(
1, Integer.MAX_VALUE, 10, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);
private final BaseFutureTask<Result> mFuture;
public BaseTask(int priority) {
mFuture = new BaseFutureTask<Result>(mWorker, priority);
}
public final BaseTask<Params, Progress, Result> execute(Params... params) {
/* Some unimportant code here */
sExecutor.execute(mFuture);
}
In BaseFutureTask class
#Override
public int compareTo(BaseFutureTask another) {
long diff = this.priority - another.priority;
return Long.signum(diff);
}
In BaseThreadPoolExecutor class i override the 3 submit methods... The constructor in this class gets called, but none of the submit methods
public class ExecutorPriority {
public static void main(String[] args) {
PriorityBlockingQueue<Runnable> pq = new PriorityBlockingQueue<Runnable>(20, new ComparePriority());
Executor exe = new ThreadPoolExecutor(1, 2, 10, TimeUnit.SECONDS, pq);
exe.execute(new RunWithPriority(2) {
#Override
public void run() {
System.out.println(this.getPriority() + " started");
try {
Thread.sleep(3000);
} catch (InterruptedException ex) {
Logger.getLogger(ExecutorPriority.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println(this.getPriority() + " finished");
}
});
exe.execute(new RunWithPriority(10) {
#Override
public void run() {
System.out.println(this.getPriority() + " started");
try {
Thread.sleep(3000);
} catch (InterruptedException ex) {
Logger.getLogger(ExecutorPriority.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println(this.getPriority() + " finished");
}
});
}
private static class ComparePriority<T extends RunWithPriority> implements Comparator<T> {
#Override
public int compare(T o1, T o2) {
return o1.getPriority().compareTo(o2.getPriority());
}
}
}
as you can guess RunWithPriority is an abstract class that is Runnable and has a Integer priority field
You can use these helper classes:
public class PriorityFuture<T> implements RunnableFuture<T> {
private RunnableFuture<T> src;
private int priority;
public PriorityFuture(RunnableFuture<T> other, int priority) {
this.src = other;
this.priority = priority;
}
public int getPriority() {
return priority;
}
public boolean cancel(boolean mayInterruptIfRunning) {
return src.cancel(mayInterruptIfRunning);
}
public boolean isCancelled() {
return src.isCancelled();
}
public boolean isDone() {
return src.isDone();
}
public T get() throws InterruptedException, ExecutionException {
return src.get();
}
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
return src.get();
}
public void run() {
src.run();
}
public static Comparator<Runnable> COMP = new Comparator<Runnable>() {
public int compare(Runnable o1, Runnable o2) {
if (o1 == null && o2 == null)
return 0;
else if (o1 == null)
return -1;
else if (o2 == null)
return 1;
else {
int p1 = ((PriorityFuture<?>) o1).getPriority();
int p2 = ((PriorityFuture<?>) o2).getPriority();
return p1 > p2 ? 1 : (p1 == p2 ? 0 : -1);
}
}
};
}
AND
public interface PriorityCallable<T> extends Callable<T> {
int getPriority();
}
AND this helper method:
public static ThreadPoolExecutor getPriorityExecutor(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS,
new PriorityBlockingQueue<Runnable>(10, PriorityFuture.COMP)) {
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
RunnableFuture<T> newTaskFor = super.newTaskFor(callable);
return new PriorityFuture<T>(newTaskFor, ((PriorityCallable<T>) callable).getPriority());
}
};
}
AND then use it like this:
class LenthyJob implements PriorityCallable<Long> {
private int priority;
public LenthyJob(int priority) {
this.priority = priority;
}
public Long call() throws Exception {
System.out.println("Executing: " + priority);
long num = 1000000;
for (int i = 0; i < 1000000; i++) {
num *= Math.random() * 1000;
num /= Math.random() * 1000;
if (num == 0)
num = 1000000;
}
return num;
}
public int getPriority() {
return priority;
}
}
public class TestPQ {
public static void main(String[] args) throws InterruptedException, ExecutionException {
ThreadPoolExecutor exec = getPriorityExecutor(2);
for (int i = 0; i < 20; i++) {
int priority = (int) (Math.random() * 100);
System.out.println("Scheduling: " + priority);
LenthyJob job = new LenthyJob(priority);
exec.submit(job);
}
}
}
I will try to explain this problem with a fully functional code. But before diving into the code I would like to explain about PriorityBlockingQueue
PriorityBlockingQueue : PriorityBlockingQueue is an implementation of BlockingQueue. It accepts the tasks along with their priority and submits the task with the highest priority for execution first. If any two tasks have same priority, then we need to provide some custom logic to decide which task goes first.
Now lets get into the code straightaway.
Driver class : This class creates an executor which accepts tasks and later submits them for execution. Here we create two tasks one with LOW priority and the other with HIGH priority. Here we tell the executor to run a MAX of 1 threads and use the PriorityBlockingQueue.
public static void main(String[] args) {
/*
Minimum number of threads that must be running : 0
Maximium number of threads that can be created : 1
If a thread is idle, then the minimum time to keep it alive : 1000
Which queue to use : PriorityBlockingQueue
*/
PriorityBlockingQueue queue = new PriorityBlockingQueue();
ThreadPoolExecutor executor = new ThreadPoolExecutor(0,1,
1000, TimeUnit.MILLISECONDS,queue);
MyTask task = new MyTask(Priority.LOW,"Low");
executor.execute(new MyFutureTask(task));
task = new MyTask(Priority.HIGH,"High");
executor.execute(new MyFutureTask(task));
}
MyTask class : MyTask implements Runnable and accepts priority as an argument in the constructor. When this task runs, it prints a message and then puts the thread to sleep for 1 second.
public class MyTask implements Runnable {
public int getPriority() {
return priority.getValue();
}
private Priority priority;
public String getName() {
return name;
}
private String name;
public MyTask(Priority priority,String name){
this.priority = priority;
this.name = name;
}
#Override
public void run() {
System.out.println("The following Runnable is getting executed "+getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
MyFutureTask class : Since we are using PriorityBlocingQueue for holding our tasks, our tasks must be wrapped inside FutureTask and our implementation of FutureTask must implement Comparable interface. The Comparable interface compares the priority of 2 different tasks and submits the task with the highest priority for execution.
public class MyFutureTask extends FutureTask<MyFutureTask>
implements Comparable<MyFutureTask> {
private MyTask task = null;
public MyFutureTask(MyTask task){
super(task,null);
this.task = task;
}
#Override
public int compareTo(MyFutureTask another) {
return task.getPriority() - another.task.getPriority();
}
}
Priority class : Self explanatory Priority class.
public enum Priority {
HIGHEST(0),
HIGH(1),
MEDIUM(2),
LOW(3),
LOWEST(4);
int value;
Priority(int val) {
this.value = val;
}
public int getValue(){
return value;
}
}
Now when we run this example, we get the following output
The following Runnable is getting executed High
The following Runnable is getting executed Low
Even though we submitted the LOW priority first, but HIGH priority task later, but since we are using a PriorityBlockingQueue, an task with a higher priority will execute first.
My solution:
public class XThreadPoolExecutor extends ThreadPoolExecutor
{
public XThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
long keepAliveTime, TimeUnit unit, PriorityBlockingQueue<Runnable> workQueue)
{
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
public XThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
long keepAliveTime, TimeUnit unit, PriorityBlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler)
{
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
}
public XThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
long keepAliveTime, TimeUnit unit, PriorityBlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory)
{
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
}
public XThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
long keepAliveTime, TimeUnit unit, PriorityBlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory, RejectedExecutionHandler handler)
{
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
}
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value)
{
return new ComparableFutureTask<>(runnable, value);
}
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable)
{
return new ComparableFutureTask<>(callable);
}
protected class ComparableFutureTask<V>
extends FutureTask<V> implements Comparable<ComparableFutureTask<V>>
{
private Object object;
public ComparableFutureTask(Callable<V> callable)
{
super(callable);
object = callable;
}
public ComparableFutureTask(Runnable runnable, V result)
{
super(runnable, result);
object = runnable;
}
#Override
#SuppressWarnings("unchecked")
public int compareTo(ComparableFutureTask<V> o)
{
if (this == o)
{
return 0;
}
if (o == null)
{
return -1; // high priority
}
if (object != null && o.object != null)
{
if (object.getClass().equals(o.object.getClass()))
{
if (object instanceof Comparable)
{
return ((Comparable) object).compareTo(o.object);
}
}
}
return 0;
}
}
}
It looks like they left that out of apache harmony. There is a svn commit log about a year ago fixing the absence of newTaskFor. You can probably just override the submit functions in an extended ThreadPoolExecutor to create an extended FutureTask that is Comparable. They are not very long.
To answer your question: The newTaskFor() method is found in ThreadPoolExecutor's superclass, AbstractExecutorService. You can simply override it in ThreadPoolExecutor, however.
This answer is a simplified version of #StanislavVitvitskyy's answer. Thanks to him.
I wanted to make the jobs that I submitted be Comparable. I created an ExecutorService with a PriorityBlockingQueue and extend it to handle the newTaskFor(...) methods:
ExecutorService pool = new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
keepAliveTime, timeUnit, new PriorityBlockingQueue<Runnable>()) {
#Override
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
return new ComparableFutureTask<T>(runnable, value);
}
#Override
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
return new ComparableFutureTask<T>(callable);
};
};
I defined a ComparableFutureTask which extends FutureTask and implements Comparable by delegating to the job.compareTo(...) that are submitted to the pool.
public class ComparableFutureTask<T> extends FutureTask<T>
implements Comparable<Object> {
private final Comparable<Object> comparableJob;
#SuppressWarnings("unchecked")
public ComparableFutureTask(Runnable runnable, T value) {
super(runnable, value);
this.comparableJob = (Comparable<Object>) runnable;
}
#SuppressWarnings("unchecked")
public ComparableFutureTask(Callable<T> callable) {
super(callable);
this.comparableJob = (Comparable<Object>) callable;
}
#Override
public int compareTo(Object o) {
return this.comparableJob
.compareTo(((ComparableFutureTask<?>) o).comparable);
}
}
This ExecutorService then can handle Runnable or Callable jobs that are also Comparable. For example:
public class MyJob implements Runnable, Comparable<MyJob> {
private int priority;
...
#Override
public int compareTo(MyJob other) {
// we want higher priority to go first
return other.priority - this.priority;
}
...
}
It is important to note that if you submit a job that is not Comparable to this queue, it will throw a ClassCastException.

Categories

Resources