The general idea is to have a Runnable running every 10 seconds in background to check some data and if needed make changes in an object. ScheduledExecutorService is instantiated in method main() and the task is scheduled. Runnable task instantiates Crawler object and starts crawling. Most of the times it runs couple of times with success but when application is running and data changes one of crawler's method is fired but never ends. There is no loop in the code. I was trying to debug also without success. Maybe you will be able to spot where the problem lays.
Main:
public class Main {
public static void main(String[] args) {
DataStock dataStock = DataStock.getInstance();
ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
ses.scheduleAtFixedRate(new EveryFiveSeconds(), 5, 5, TimeUnit.SECONDS);
// below the task which fails after couple of runs
ses.scheduleAtFixedRate(new EveryTenSeconds(), 1 , 10, TimeUnit.SECONDS);
dataStock.init();
Menu currentScreen = new UserMenu();
while(currentScreen != null) {
currentScreen = currentScreen.display();
}
}
}
EveryTenSeconds Runnable:
public class EveryTenSeconds implements Runnable {
#Override
public void run() {
Crawler crawler = new Crawler();
crawler.crawl();
}
}
Crawler:
public class Crawler {
private final DataStock dataStock;
public Crawler() {
this.dataStock = DataStock.getInstance();
}
public void crawl() {
checkOutRentables(dataStock.getCarServicesWithOwners().keySet());
checkFinancialBook(dataStock.getPaymentsBook(), dataStock.getCurrentDate());
}
private void checkOutRentables(Set<CarService> carServices) {
System.out.println("Start check...");
carServices.stream()
.flatMap(service -> service.getWarehousesSet().stream())
.filter(rentable -> !rentable.isAvailableForRent())
.forEach(RentableArea::refreshCurrentState);
System.out.println("Checking finished");
}
private void checkFinancialBook(Set<BookEntry> bookEntries, LocalDate currentDate) {
System.out.println("Start second check...");
bookEntries.stream()
.filter(bookEntry -> currentDate.isAfter(bookEntry.getPaymentDeadline()) && !bookEntry.isPaid() && !bookEntry.isNotified())
.forEach(BookEntry::notifyDebtor);
System.out.println("Finished second check..."); //this line never shows in one of runs and the task is never repeated again...
}
}
BookEntry
public class BookEntry {
private final UUID rentableId = UUID.randomUUID();
private final UUID personId;
private final UUID id;
private final BigDecimal amountDue;
private final LocalDate paymentDeadline;
private boolean paid = false;
private boolean notified = false;
public BookEntry(UUID personId, UUID id, BigDecimal amountDue, LocalDate paymentDeadline) {
this.personId = personId;
this.id = id;
this.amountDue = amountDue;
this.paymentDeadline = paymentDeadline;
}
public UUID getRentableId() {
return rentableId;
}
public UUID getPersonId() {
return personId;
}
public UUID getId() {
return id;
}
public BigDecimal getAmountDue() {
return amountDue;
}
public LocalDate getPaymentDeadline() {
return paymentDeadline;
}
public boolean isPaid() {
return paid;
}
public boolean isNotified() {
return notified;
}
public void settlePayment() {
if(!paid) {
paid = true;
}
else {
throw new IllegalStateException("This is already paid man!");
}
}
public void notifyDebtor() {
if(!notified) {
notified = true;
DataStock dataStock = DataStock.getInstance();
Person debtor = dataStock.getPeople().stream()
.filter(person -> person.getId().equals(personId))
.findFirst()
.orElseThrow();
debtor.alert(new TenantAlert(personId, rentableId, dataStock.getCurrentDate(), amountDue));
}
}
}
It seems that the answer is easy - whenever the task scheduled in ScheduledExecutorService throws an exception the task is halted and never repeated. Also the exception is not thrown visibly. The easiest way to avoid such situation is to have try-catch block in run() ,method of Runnable. Please have a look at this post: ScheduledExecutorService handling exceptions
i am trying to simulate visitors going into a theater and taking an aailable sit(the number of available sits is shared) and once all the sits are taken the rest go to sleep.
i am having trouble over the availablesits variable in the getsit method inside the visitor class.
please help me
i tried synchronizing the threads as well as making the variable volatile. but for some reasons all threads arrive to that getsit part at the same time? i dont understand why!
//main
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
int numVisitors = 23;
int theaterCapacity =5;
int party_ticket=3;
Clock clock = new Clock();
Theater theater=new Theater(theaterCapacity,clock);
ArrayList<Visitor> visitorlist = new ArrayList<Visitor>();
for(int i=1;i<=numVisitors;i++) {
visitorlist.add(new Visitor(i,clock,theater));
}
clock.start();
for(Visitor visitor:visitorlist)
visitor.start();
}
}
//visitor class
public class Visitor extends Thread{
private static Clock clock;
private static Theater theater;
public int id;
public boolean sawPresentation=false;
public volatile int priority= 10;
public static long time = System.currentTimeMillis();
public void msg(String m) {
System.out.println("["+(System.currentTimeMillis()-time)+"] "+getName()+": "+m);
}
Visitor(int id, Clock clock, Theater theater){
this.id=id;
this.clock=clock;
this.theater=theater;
}
public void run(){
heArrives();
while(!sawPresentation) {
while(!clock.presentationIsOpen()) {
//busy wait
}
getASit();
}
}
public void heArrives() {
msg("the visitor arrived");
}
public synchronized void getASit(){
if(theater.availableSits>0){
msg("the visitor got a sit");
theater.availableSits--;
watchPresentation();
}
}
public void watchPresentation(){
msg("the visitor is watching the presentation");
}
}
//clock class
import java.util.Timer;
import java.util.TimerTask;
public class Clock extends Thread {
public static long time = System.currentTimeMillis();
public static int secondsPassed=6;
Timer timer= new Timer();
TimerTask task = new TimerTask() {
#Override
public void run() {
secondsPassed++;
//System.out.println("seconds passed: "+secondsPassed);
}
};
public void run(){
timer.scheduleAtFixedRate(task,0,1000);
}
public boolean presentationIsOpen(){
if(secondsPassed%6==0) return true;
return false;
}
}
//theater class
class Theater extends Thread{
public static Clock clock;
public int capacity;
public volatile int availableSits=5;
Theater(int capacity,Clock clock){
this.capacity=capacity;
this.clock=clock;
}
}
Your main problem is the synchronization of the getASit method.You are synchronizing against Visitor object instance so every thread synchronized against diferent object. Instead you have to synchronized against the object that is shared. In your case against the theater. Change your method to something like this:
public void getASit(){
synchronized(theater){
if(theater.availableSits>0){
msg("the visitor got a sit");
theater.availableSits--;
watchPresentation();
}
}
}
Its better not to use busy wait, its burn cpu too much, better is to use sleep for example:
while(!clock.presentationIsOpen()) {
try {
Thread.sleep(1_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
I'm looking for a java collection that supports blocking read()s on a predicate. I wrote a simple version but it seems like this must have been invented already?
For example:
interface PredicateConsumerCollection<T> {
public void put(T t);
#Nullable
public T get(Predicate<T> p, long millis) throws InterruptedException;
}
put() delivers its argument to a waiting consumer with a matching predicate, or stashes it in a store. A get() returns immediately if a suitable T is already in the store, or blocks till a suitable value is put(), or times out. Consumers compete but fairness isn't critical in my case.
Anyone aware of a such a collection?
There is no immediate class that can solve your problem, but a combination of a ConcurrentHashMap and a BlockingQueue could be a solution.
The hash map is defined as:
final ConcurrentHashMap<Predicate, LinkedBlockingQueue<Result>> lookup;
The put needs to ensure, that for each Predicate a queue is added to the map, this can be done thread-safe using putIfAbsent.
If you have a fixed set of Predicates, you can simply pre-fill the list, then a Consumer can simply call lookup.get(Predicate).take()
If the amount of Predicates is unknown/too many, you need to write a wait/notify implementation for Consumers in case a Predicate is not yet in the list on your own.
I also need something very similar for testing that a certain JMS asynchronous message has been received within a certain timeout. It turns out that your question is relatively easy to implement by using basic wait/notify as explained in the Oracle tutorials. The idea is to make the put and query methods synchronized and let the query method do a wait. The put method calls notifyAll to wake up any waiting threads in the query method. The query method must then check if the predicate is matched. The most tricky thing is getting the timeout right due to waking up when the predicate does not match and due to possible " spurious wakeups". I found this stackoverflow post that provides the answer.
Here is the implementation I came up with:
import java.util.ArrayList;
import java.util.List;
// import net.jcip.annotations.GuardedBy;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
public class PredicateConsumerCollectionImpl<T> implements
PredicateConsumerCollection<T> {
// #GuardedBy("this")
private List<T> elements = new ArrayList<>();
#Override
public synchronized void put(T t) {
elements.add(t);
notifyAll();
}
#Override
public synchronized T query(Predicate<T> p, long millis)
throws InterruptedException {
T match = null;
long nanosOfOneMilli = 1000000L;
long endTime = System.nanoTime() + millis * nanosOfOneMilli;
while ((match = Iterables.find(elements, p, null)) == null) {
long sleepTime = endTime - System.nanoTime();
if (sleepTime <= 0) {
return null;
}
wait(sleepTime / nanosOfOneMilli,
(int) (sleepTime % nanosOfOneMilli));
}
return match;
}
synchronized boolean contains(T t) {
return elements.contains(t);
}
}
And here is a JUnit test that proves that the code works as intended:
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.junit.Before;
import org.junit.Test;
import com.google.common.base.Predicate;
/**
* Unit test for the {#link PredicateConsumerCollection} implementation.
*
* <p>
* The tests act as consumers waiting for the test Producer to put a certain
* String.
*/
public class PredicateConsumerCollectionTest {
private static class Producer implements Runnable {
private PredicateConsumerCollection<String> collection;
public Producer(PredicateConsumerCollection<String> collection) {
this.collection = collection;
collection.put("Initial");
}
#Override
public void run() {
try {
int millis = 50;
collection.put("Hello");
Thread.sleep(millis);
collection.put("I");
Thread.sleep(millis);
collection.put("am");
Thread.sleep(millis);
collection.put("done");
Thread.sleep(millis);
collection.put("so");
Thread.sleep(millis);
collection.put("goodbye!");
} catch (InterruptedException e) {
e.printStackTrace();
fail("Unexpected InterruptedException");
}
}
}
private PredicateConsumerCollectionImpl<String> collection;
private Producer producer;
#Before
public void setup() {
collection = new PredicateConsumerCollectionImpl<>();
producer = new Producer(collection);
}
#Test(timeout = 2000)
public void wait_for_done() throws InterruptedException {
assertTrue(collection.contains("Initial"));
assertFalse(collection.contains("Hello"));
Thread producerThread = new Thread(producer);
producerThread.start();
String result = collection.query(new Predicate<String>() {
#Override
public boolean apply(String s) {
return "done".equals(s);
}
}, 1000);
assertEquals("done", result);
assertTrue(collection.contains("Hello"));
assertTrue(collection.contains("done"));
assertTrue(producerThread.isAlive());
assertFalse(collection.contains("goodbye!"));
producerThread.join();
assertTrue(collection.contains("goodbye!"));
}
#Test(timeout = 2000)
public void wait_for_done_immediately_happens() throws InterruptedException {
Thread producerThread = new Thread(producer);
producerThread.start();
String result = collection.query(new Predicate<String>() {
#Override
public boolean apply(String s) {
return "Initial".equals(s);
}
}, 1000);
assertEquals("Initial", result);
assertFalse(collection.contains("I"));
producerThread.join();
assertTrue(collection.contains("goodbye!"));
}
#Test(timeout = 2000)
public void wait_for_done_never_happens() throws InterruptedException {
Thread producerThread = new Thread(producer);
producerThread.start();
assertTrue(producerThread.isAlive());
String result = collection.query(new Predicate<String>() {
#Override
public boolean apply(String s) {
return "DONE".equals(s);
}
}, 1000);
assertEquals(null, result);
assertFalse(producerThread.isAlive());
assertTrue(collection.contains("goodbye!"));
}
}
trying to make an lru map by subclassing linked hash map.
the map is run through collections.synchronized.
all usages of the map are surrounded by a synchronized block. the unit test also fails if they are all removed. one would think they are not necessary since the map was run through collections.synchronized.
one thread puts sequential numbers (0,1,2,3 ...) into the map. removals are handled by removed eldest entry. no one else removes entries from the map.
the other thread gets the data from the map.
the following unit test fails usually at "oops". this is when a non zero number shows up in the first position (it should be zero until the map gets full). other strange things can happen like null values in the entry set.
any pointers will be appreciated.
thanks
import static org.junit.Assert.*;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
class LruMap<K,V> extends LinkedHashMap<K,V> {
public LruMap() {
super(defaultMaxSize+1,.75f,true);
maxSize=defaultMaxSize;
}
public LruMap(int arg0) {
super(arg0+1,.75f,true);
maxSize=arg0;
}
public LruMap(int arg0,float arg1) {
super(arg0+1,arg1,true);
maxSize=arg0;
}
public LruMap(int arg0,float arg1,boolean arg2) {
super(arg0+1,arg1,arg2);
if(!arg2)
throw new RuntimeException("you did not construct an lru map!");
maxSize=arg0;
}
public LruMap(Map<K,V> arg0) {
super(arg0);
throw new RuntimeException("you did not construct an lru map!");
}
public boolean removeEldestEntry(Map.Entry<K,V> eldest) {
return size()>maxSize;
}
public final int maxSize;
public static final int defaultMaxSize=2048;
static final long serialVersionUID=0;
}
class Server implements Runnable {
public Server(final int pieces,final int period) {
this.pieces=pieces;
this.period=period;
lruMap=Collections.synchronizedMap(new LruMap<Long,Long>(3*pieces/2));
}
#Override public void run() {
t0=System.currentTimeMillis();
while(piece<stopAtPiece) {
final long dt=System.currentTimeMillis()-t0;
final long target=piece(dt);
System.out.println("adding "+(target-piece+1)+" items");
for(;piece<=target;piece++) {
synchronized(lruMap) {
lruMap.put(piece,piece);
}
}
checkMap(piece,true);
try {
Thread.sleep(100);
} catch(InterruptedException e) {
e.printStackTrace();
break;
}
}
}
Map.Entry<Long,Long>[] checkMap(final long n,boolean print) {
synchronized(lruMap) {
Map.Entry<Long,Long>[] entries=null;
if(lruMap.size()>0) {
final Set<Map.Entry<Long,Long>> entrySet=lruMap.entrySet();
entries=new Map.Entry[entrySet.size()];
entrySet.toArray(entries);
long first=entries[0].getKey();
long last=entries[entries.length-1].getKey();
if(print)
for(Map.Entry<Long,Long> entry:entries)
System.out.print(entry.getKey()+" ");
System.out.println();
if(n<pieces&&first!=0) {
System.out.println("lru: first!=0! "+first);
if(throwWhenfirstIsNotZero) { throw new RuntimeException("oops"); }
}
for(int i=0;i<entries.length-1;i++) {
long p0=entries[i].getKey();
long p1=entries[i+1].getKey();
if(p0>p1)
System.out.println("out of order! "+p0+" "+p1);
else if(p0==p1)
System.out.println("dupicate "+p0+" "+p1);
else if(p0+1==p1)
; // ok
else if(p0+1<p1)
System.out.println("skipped "+p0+" "+p1);
else System.out.println("some case i mssed!");
}
}
return entries;
}
}
public long piece(final long dt) {
return dt/period*pieces+dt%period*pieces/period;
}
public boolean throwWhenfirstIsNotZero=true;
protected long piece;
public long t0;
protected long stopAtPiece=Long.MAX_VALUE;
public final int period;
public final int pieces;
public final Map<Long,Long> lruMap;
}
public class ServerTestCase {
#Before public void setUp() throws Exception {}
#After public void tearDown() throws Exception {}
#Test public void testRun() {
server.stopAtPiece=server.pieces;
server.throwWhenfirstIsNotZero=true;
Thread thread=new Thread(server);
thread.setName("server");
thread.start();
while(thread.isAlive()) {
for(long i=0;i<server.piece;i++)
synchronized(server.lruMap) {
server.lruMap.get(i);
}
}
}
final int period=2*1000;
final int serverPieces=100;
Server server=new Server(serverPieces,period);
}
If you are accessing the collection inside a synchronized(lruMap) block, then you probably don't want to wrap it in Collections.synchronizedMap() - use one or the other. This is because they will probably be using different locks - in fact it's almost certain, because it's extremely unlikely that synchronizedMap() is using synchronized(this) internally.
Also I recommend enter link description here
I am implementing a thread pooling mechanism in which I'd like to execute tasks of varying priorities. I'd like to have a nice mechanism whereby I can submit a high priority task to the service and have it be scheduled before other tasks. The priority of the task is an intrinsic property of the task itself (whether I express that task as a Callable or a Runnable is not important to me).
Now, superficially it looks like I could use a PriorityBlockingQueue as the task queue in my ThreadPoolExecutor, but that queue contains Runnable objects, which may or may not be the Runnable tasks I've submitted to it. Moreover, if I've submitted Callable tasks, it's not clear how this would ever map.
Is there a way to do this? I'd really rather not roll my own for this, since I'm far more likely to get it wrong that way.
(An aside; yes, I'm aware of the possibility of starvation for lower-priority jobs in something like this. Extra points (?!) for solutions that have a reasonable guarantee of fairness)
I have solved this problem in a reasonable fashion, and I'll describe it below for future reference to myself and anyone else who runs into this problem with the Java Concurrent libraries.
Using a PriorityBlockingQueue as the means for holding onto tasks for later execution is indeed a movement in the correct direction. The problem is that the PriorityBlockingQueue must be generically instantiated to contain Runnable instances, and it is impossible to call compareTo (or similiar) on a Runnable interface.
Onto solving the problem. When creating the Executor, it must be given a PriorityBlockingQueue. The queue should further be given a custom Comparator to do proper in place sorting:
new PriorityBlockingQueue<Runnable>(size, new CustomTaskComparator());
Now, a peek at CustomTaskComparator:
public class CustomTaskComparator implements Comparator<MyType> {
#Override
public int compare(MyType first, MyType second) {
return comparison;
}
}
Everything looking pretty straight forward up to this point. It gets a bit sticky here. Our next problem is to deal with the creation of FutureTasks from the Executor. In the Executor, we must override newTaskFor as so:
#Override
protected <V> RunnableFuture<V> newTaskFor(Callable<V> c) {
//Override the default FutureTask creation and retrofit it with
//a custom task. This is done so that prioritization can be accomplished.
return new CustomFutureTask(c);
}
Where c is the Callable task that we're trying to execute. Now, let's have a peek at CustomFutureTask:
public class CustomFutureTask extends FutureTask {
private CustomTask task;
public CustomFutureTask(Callable callable) {
super(callable);
this.task = (CustomTask) callable;
}
public CustomTask getTask() {
return task;
}
}
Notice the getTask method. We're gonna use that later to grab the original task out of this CustomFutureTask that we've created.
And finally, let's modify the original task that we were trying to execute:
public class CustomTask implements Callable<MyType>, Comparable<CustomTask> {
private final MyType myType;
public CustomTask(MyType myType) {
this.myType = myType;
}
#Override
public MyType call() {
//Do some things, return something for FutureTask implementation of `call`.
return myType;
}
#Override
public int compareTo(MyType task2) {
return new CustomTaskComparator().compare(this.myType, task2.myType);
}
}
You can see that we implement Comparable in the task to delegate to the actual Comparator for MyType.
And there you have it, customized prioritization for an Executor using the Java libraries! It takes some bit of bending, but it's the cleanest that I've been able to come up with. I hope this is helpful to someone!
At first blush it would seem you could define an interface for your tasks that extends Runnable or Callable<T> and Comparable. Then wrap a ThreadPoolExecutor with a PriorityBlockingQueue as the queue, and only accept tasks that implement your interface.
Taking your comment into account, it looks like one option is to extend ThreadPoolExecutor, and override the submit() methods. Refer to AbstractExecutorService to see what the default ones look like; all they do is wrap the Runnable or Callable in a FutureTask and execute() it. I'd probably do this by writing a wrapper class that implements ExecutorService and delegates to an anonymous inner ThreadPoolExecutor. Wrap them in something that has your priority, so that your Comparator can get at it.
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(timeout, unit);
}
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));
task = new MyTask(Priority.MEDIUM,"Medium");
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 Medium
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, any task with a higher priority will execute first.
My solution preserves submition order of tasks for same priorities. It's an improvement of this answer
Task execution order is based on:
Priority
Submit order (within same priority)
Tester class:
public class Main {
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService executorService = PriorityExecutors.newFixedThreadPool(1);
//Priority=0
executorService.submit(newCallable("A1", 200)); //Defaults to priority=0
executorService.execute(newRunnable("A2", 200)); //Defaults to priority=0
executorService.submit(PriorityCallable.of(newCallable("A3", 200), 0));
executorService.submit(PriorityRunnable.of(newRunnable("A4", 200), 0));
executorService.execute(PriorityRunnable.of(newRunnable("A5", 200), 0));
executorService.submit(PriorityRunnable.of(newRunnable("A6", 200), 0));
executorService.execute(PriorityRunnable.of(newRunnable("A7", 200), 0));
executorService.execute(PriorityRunnable.of(newRunnable("A8", 200), 0));
//Priority=1
executorService.submit(PriorityRunnable.of(newRunnable("B1", 200), 1));
executorService.submit(PriorityRunnable.of(newRunnable("B2", 200), 1));
executorService.submit(PriorityCallable.of(newCallable("B3", 200), 1));
executorService.execute(PriorityRunnable.of(newRunnable("B4", 200), 1));
executorService.submit(PriorityRunnable.of(newRunnable("B5", 200), 1));
executorService.shutdown();
}
private static Runnable newRunnable(String name, int delay) {
return new Runnable() {
#Override
public void run() {
System.out.println(name);
sleep(delay);
}
};
}
private static Callable<Integer> newCallable(String name, int delay) {
return new Callable<Integer>() {
#Override
public Integer call() throws Exception {
System.out.println(name);
sleep(delay);
return 10;
}
};
}
private static void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
}
}
Result:
A1 B1 B2 B3 B4 B5 A2 A3 A4 A5 A6 A7 A8
First task is A1 because there were no higher priority in the queue when it was inserted. B tasks are 1 priority so executed earlier, A tasks are 0 priority so executed later, but execution order is follows submition order: B1, B2, B3, ... A2, A3, A4 ...
The solution:
public class PriorityExecutors {
public static ExecutorService newFixedThreadPool(int nThreads) {
return new PriorityExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS);
}
private static class PriorityExecutor extends ThreadPoolExecutor {
private static final int DEFAULT_PRIORITY = 0;
private static AtomicLong instanceCounter = new AtomicLong();
#SuppressWarnings({"unchecked"})
public PriorityExecutor(int corePoolSize, int maximumPoolSize,
long keepAliveTime, TimeUnit unit) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, (BlockingQueue) new PriorityBlockingQueue<ComparableTask>(10,
ComparableTask.comparatorByPriorityAndSequentialOrder()));
}
#Override
public void execute(Runnable command) {
// If this is ugly then delegator pattern needed
if (command instanceof ComparableTask) //Already wrapped
super.execute(command);
else {
super.execute(newComparableRunnableFor(command));
}
}
private Runnable newComparableRunnableFor(Runnable runnable) {
return new ComparableRunnable(ensurePriorityRunnable(runnable));
}
#Override
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
return new ComparableFutureTask<>(ensurePriorityCallable(callable));
}
#Override
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
return new ComparableFutureTask<>(ensurePriorityRunnable(runnable), value);
}
private <T> PriorityCallable<T> ensurePriorityCallable(Callable<T> callable) {
return (callable instanceof PriorityCallable) ? (PriorityCallable<T>) callable
: PriorityCallable.of(callable, DEFAULT_PRIORITY);
}
private PriorityRunnable ensurePriorityRunnable(Runnable runnable) {
return (runnable instanceof PriorityRunnable) ? (PriorityRunnable) runnable
: PriorityRunnable.of(runnable, DEFAULT_PRIORITY);
}
private class ComparableFutureTask<T> extends FutureTask<T> implements ComparableTask {
private Long sequentialOrder = instanceCounter.getAndIncrement();
private HasPriority hasPriority;
public ComparableFutureTask(PriorityCallable<T> priorityCallable) {
super(priorityCallable);
this.hasPriority = priorityCallable;
}
public ComparableFutureTask(PriorityRunnable priorityRunnable, T result) {
super(priorityRunnable, result);
this.hasPriority = priorityRunnable;
}
#Override
public long getInstanceCount() {
return sequentialOrder;
}
#Override
public int getPriority() {
return hasPriority.getPriority();
}
}
private static class ComparableRunnable implements Runnable, ComparableTask {
private Long instanceCount = instanceCounter.getAndIncrement();
private HasPriority hasPriority;
private Runnable runnable;
public ComparableRunnable(PriorityRunnable priorityRunnable) {
this.runnable = priorityRunnable;
this.hasPriority = priorityRunnable;
}
#Override
public void run() {
runnable.run();
}
#Override
public int getPriority() {
return hasPriority.getPriority();
}
#Override
public long getInstanceCount() {
return instanceCount;
}
}
private interface ComparableTask extends Runnable {
int getPriority();
long getInstanceCount();
public static Comparator<ComparableTask> comparatorByPriorityAndSequentialOrder() {
return (o1, o2) -> {
int priorityResult = o2.getPriority() - o1.getPriority();
return priorityResult != 0 ? priorityResult
: (int) (o1.getInstanceCount() - o2.getInstanceCount());
};
}
}
}
private static interface HasPriority {
int getPriority();
}
public interface PriorityCallable<V> extends Callable<V>, HasPriority {
public static <V> PriorityCallable<V> of(Callable<V> callable, int priority) {
return new PriorityCallable<V>() {
#Override
public V call() throws Exception {
return callable.call();
}
#Override
public int getPriority() {
return priority;
}
};
}
}
public interface PriorityRunnable extends Runnable, HasPriority {
public static PriorityRunnable of(Runnable runnable, int priority) {
return new PriorityRunnable() {
#Override
public void run() {
runnable.run();
}
#Override
public int getPriority() {
return priority;
}
};
}
}
}
Would it be possible to have one ThreadPoolExecutor for each level of priority? A ThreadPoolExecutor can be instanciated with a ThreadFactory and you could have your own implementation of a ThreadFactory to set the different priority levels.
class MaxPriorityThreadFactory implements ThreadFactory {
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
thread.setPriority(Thread.MAX_PRIORITY);
}
}