I need to override execute method of executor where I need to change the behavior that threads more than core pool size will be created only when queue is full.
However in real time applications this behavior is undesirable as it can lead to unending wait of task present in queue.
I have changed the execute method as below:
public void execute(Runnable command)
{
System.out.println("ActiveCount : " + getActiveCount() + " PoolSize : " + getPoolSize()
+ " QueueSize : " + getQueue().size() +" Idle Threads : " +(getPoolSize()-getActiveCount()));
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
else if (isRunning(c) && workQueue.offer(command))
{
int recheck = ctl.get();
if (getActiveCount() < workerCountOf(recheck) && isRunning(recheck) && workQueue.offer(command)) {
return;
}
if (addWorker(command, false)) {
return;
}
else if (! isRunning(recheck) && remove(command))
{
reject(command);
}
else if (workerCountOf(recheck) == 0)
{
addWorker(null, false);
}
}
else
{
reject(command); // add task to the queue
}
}
Trying to achieve:
CoreThreads -> Non-CoreThreads -> Queue instead of CoreThreads -> Queue -> Non-CoreThreads.
I dont understand why you need to change execute method, I think, max pool size should not be preferred over queue, as I can see in you code.
I had same problem and you can follow the link :
click to follow the thread.
I feel this should be you last choice, try something else first.
Related
I'm little confused with tasks in Java multithreading.
Namely, I've 15 objects, which implements Callable and i'm submitting it by ExecutorService. Each Callable has its own progress bar with is updating in for loop with setProgress method.
I want to show 3 of 15 callables which will finish their job in first, second and third position by getting their names and setting it to labels on my scene. Of course each callable has different working time.
I created Task and i'm starting it in new thread and iterating over list of future tasks from my ExecutorService.
The problem is that my labels aren't visible until first element of the future list is true (until first thread is finished). I have really no idea why and i would be very grateful for your help.
public void startButtonClicked() {
Task task = new Task<Void>() {
#Override
public Void call() {
int i = 0;
while (i < 3) {
for (Future<Boolean> future : futures) {
try {
if (future.get() == true && i == 0) {
labelFirst.setVisible(true);
i++;
}
if (future.get() == true && i == 1) {
labelSecond.setVisible(true);
i++;
}
if (future.get() == true && i == 2) {
labelThird.setVisible(true);
i++;
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
return null;
}
};
for (Callable c : callables) {
futures.add(executorService.submit(c));
}
new Thread(task).start();
executorService.shutdown();
}
In my ideal solution each label will become visible when their callable will finish, so labelSecond should appear some time after labelFirst.
It's my call method in my callable:
public Boolean call() {
double raceTime = ThreadLocalRandom.current().nextDouble(45.0, 60.0);
try {
for (double i = 0; i < raceTime; i += 0.01) {
TimeUnit.MILLISECONDS.sleep(1);
progressBar.setProgress(i / raceTime);
}
} catch (ParseException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return true;
}
EDIT:
With checking future.isDone() and little changes it works as i wished.
public void startButtonClicked() {
Task task = new Task<Void>() {
#Override
public Void call() {
int i = 0;
while (i < 3) {
i = 0;
for (Future<Boolean> future : futures) {
if (future.isDone() == true) i++;
if (i == 1) {
labelFirst.setVisible(true);
labelFirstCyclistName.setVisible(true);
}
if (i == 2) {
labelSecond.setVisible(true);
labelSecondCyclistName.setVisible(true);
}
if (i == 3) {
labelThird.setVisible(true);
labelThirdCyclistName.setVisible(true);
}
}
}
return null;
}
};
for (Cyclist c : cyclists) {
futures.add(executorService.submit(c));
}
new Thread(task).start();
executorService.shutdown();
}
The problem is that my labels aren't visible until first element of
the future list is true (until first thread is finished). I have
really no idea why and i would be very grateful for your help.
According to the documentation of Future#get
Waits if necessary for the computation to complete, and then retrieves
its result.
Here is your code - pay special attention to a line containing future.get():
public Void call() {
int i = 0;
while (i < 3) {
for (Future<Boolean> future : futures) {
try {
if (future.get() == true && i == 0) {
During the first iteration of the loop the first future is retrieved from futures, and then future.get() stops the execution of the loop and waits (holds) until execution of this first future (the first thread) will finish and will return a result.
Then the loop continues and LabelX..setVisible(true); are called making labels visible.
I have a PublishSubject with this configuration:
PublishSubject<Message> messageObserver =
messageObserver
.filter(t -> test(t))
.buffer(eventsSaveTimeSpanInSeconds, TimeUnit.SECONDS, eventsSaveCount)
.subscribe(messages -> saveToDB(messages));
Different threads of my application are writing messages to this PublishSubject via onNext().
As I see, the buffer underlying ObservableBufferTimed.BufferExactBoundedObserver is non thread-safe, because its onNext looks as follows:
public void onNext(T t) {
U b;
synchronized (this) {
b = buffer;
if (b == null) {
return;
}
b.add(t);
if (b.size() < maxSize) {
return;
}
buffer = null;
producerIndex++;
}
if (restartTimerOnMaxSize) {
timer.dispose();
}
fastPathOrderedEmit(b, false, this);
try {
b = ObjectHelper.requireNonNull(bufferSupplier.call(), "The buffer supplied is null");
} catch (Throwable e) {
Exceptions.throwIfFatal(e);
actual.onError(e);
dispose();
return;
}
synchronized (this) {
buffer = b;
consumerIndex++;
}
if (restartTimerOnMaxSize) {
timer = w.schedulePeriodically(this, timespan, timespan, unit);
}
}
To make the race condition case more obvious I set the eventsSaveTimeSpanInSeconds and eventsSaveCountparams to 1 (1 event in 1 second).
The problem appears in this block:
synchronized (this) {
b = buffer;
if (b == null) {
return;
}
b.add(t);
if (b.size() < maxSize) {
return;
}
buffer = null;
producerIndex++;
}
So, if two messages are buffering at the same time then first message fills the buffer and assigns null to buffer variable. New buffer will be initialized later after the synchronized block. If there is a race condition, when the buffer is null, the second message will not buffered because of the code:
if (b == null) {
return;
}
Is this a defect or a corrrect buffer behavior? How can I avoid this situation?
Use a serialized subject if multiple threads want to call onNext:
Subject<Message> messageObserver = PublishSubject.<Message>create().toSerialized();
messageObserver
.filter(t -> test(t))
.buffer(eventsSaveTimeSpanInSeconds, TimeUnit.SECONDS, eventsSaveCount)
.subscribe(messages -> saveToDB(messages));
// from any thread now
messageObserver.onNext(message);
I glanced at execute method of ThreadPoolExecutor class. This seems to be very short and simple:
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {
if (runState == RUNNING && workQueue.offer(command)) {
if (runState != RUNNING || poolSize == 0)
ensureQueuedTaskHandled(command);
}
else if (!addIfUnderMaximumPoolSize(command))
reject(command); // is shutdown or saturated
}
}
But nothing seems to be happening if the the condition poolSize >= corePoolSize is satisfied!
Because of if the first part of a ORcondition is true, the second won't be executed:
if (true || anyMethodWillNotBeExecuted()) { ... }
According to the rules for thread creation, here also is maximumPoolSize. And in case if the number of threads is equal (or greater than) the corePoolSize and less than maxPoolSize the new thread should be created for task or task should be added to queue.
So why in case when poolSize greater than or equals to corePoolSize nothing should happen?..
addIfUnderCorePoolSize will create a new "core" thread for this executor.
If number of threads in the executor (poolSize) is already greater than or equal to number of "core" threads (corePoolSize), then obviously there is no need to create more "core" threads.
Maybe expanding OR condition will be a bit clearer:
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
if (poolSize >= corePoolSize) {
// there are enough core threads
// let's try to put task on the queue
if (runState == RUNNING && workQueue.offer(command)) {
if (runState != RUNNING || poolSize == 0)
ensureQueuedTaskHandled(command);
} else if (!addIfUnderMaximumPoolSize(command))
reject(command); // is shutdown or saturated
} else if (addIfUnderCorePoolSize(command)) {
// there was not enough core threads, so we started one
// the task is being executed on a new thread, so there's nothing else to be done here
return;
} else {
// there are enough core threads
// but we could not start a new thread
// so let's try to add it to the queue
if (runState == RUNNING && workQueue.offer(command)) {
if (runState != RUNNING || poolSize == 0)
ensureQueuedTaskHandled(command);
} else if (!addIfUnderMaximumPoolSize(command))
reject(command); // is shutdown or saturated
}
}
In my method under the if statement:
if (currentLocationX == 0 && currentLocationY == 4)
I have a break statement that should make the program exit out of the while loop and return true for 'answer' and for the method. Yet after some testing it seems that after returning true for 'answer', it goes back into the while loop giving the wrong results int the end. Why is my break statement not doing what it's supposed to? Thank you!
P.S. (this method calls on some other method that were not relevant to mention here)
public boolean solveMaze()
{
boolean answer = false;
int currentLocationX;
int currentLocationY;
//push starting location
pushX(2);
pushY(1);
while((isEmptyX() == false) && (isEmptyY() == false))
{
printMaze();
System.out.println();
currentLocationX = popX();
currentLocationY = popY();
//mark current location as visited
visited(currentLocationX, currentLocationY, maze);
System.out.println("Current Location: " + currentLocationX + ", " + currentLocationY);
if (currentLocationX == 0 && currentLocationY == 4)
{
answer = true;
break;
}
else
{
//push all unvisited OPEN neighbor locations into stack
if (checkEast(currentLocationX, currentLocationY) == 0)
{
pushX(eastX(currentLocationX));
pushY(eastY(currentLocationY));
}
else;
if (checkSouth(currentLocationX, currentLocationY)== 0)
{
pushX(southX(currentLocationX));
pushY(southY(currentLocationY));
}
else;
if (checkWest(currentLocationX, currentLocationY)== 0)
{
pushX(westX(currentLocationX));
pushY(westY(currentLocationY));
}
else;
if (checkNorth(currentLocationX, currentLocationY)== 0)
{
pushX (northX(currentLocationX));
pushY(northY(currentLocationY));
}
else;
}
}
return answer;
}
I wrote out the basic logic of your method as
public static boolean solveMaze() {
boolean answer = false;
int currentLocationX = 0;
int currentLocationY = 4;
while (true) {
if (currentLocationX == 0 && currentLocationY == 4) {
System.out.println("Hit the break");
break;
} else {
System.out.println("Missed the break");
}
}
return answer;
}
and if you execute it you get Hit the break. So your solveMaze() method is fine in terms of breaking out of the loop once it satisfies your if-statement. I would say that if you see your code subsequently going back into the while loop, it must be that solveMaze() was called a second time.
Code is too large, so I'll just copy the part that is problematic.
This is run() method in one class:
public void run(){
try{
sleep(1000);
while(true){
synchronized(space){
if(end)
return;
if(space[X][Y] == null)
break;
if(((Ship)space[X][Y]).isDestroyed){
destroy();
break;
}
if(isThereAnyShipsInTheArea() != 0){
if(team != ((Ship)space[X][Y + isThereAnyShipsInTheArea()]).team){
fight(isThereAnyShipsInTheArea());
}
}
else
move();
if(isDestroyed){
destroy();
break;
}
}
}
}
catch(InterruptedException ie){
System.out.println("Interrupted exception!");
}
}
This is simulation of Star Trek. Variable team represends to which team the ship belongs. Varable isDestroyed is true if the ship is destroyed in battle or crash when moving.
isThereAnyShipsInTheArea() - ship is within range if the distance one or two.
space is matrix whit dimensions [90]x[90].
I think problem is in run method, but I'll give you some other methods.
private int isThereAnyShipsInTheArea(){
if(space[X][Y - 2] instanceof Ship && ((Ship)space[X][Y - 2]).isDestroyed == false)
return -2;
if(space[X][Y - 1] instanceof Ship && ((Ship)space[X][Y - 1]).isDestroyed == false)
return -1;
if(space[X][Y + 1] instanceof Ship && ((Ship)space[X][Y + 1]).isDestroyed == false)
return 1;
if(space[X][Y + 2] instanceof Ship && ((Ship)space[X][Y + 2]).isDestroyed == false)
return 2;
return 0;
}
private synchronized void fight(int meet){
while(((Ship)svemir[X][Y]).isDestroyed == false && ((Ship)space[X][Y + meet]).isDestroyed == false){
if(((Ship)space[X][Y]).getProjectile() != 0){
((Ship)space[X][Y + meet]).setShield(((Ship)space[X][Y + meet]).getShield() - 1);
((Ship)space[X][Y + meet]).setWarp(((Ship)space[X][Y + meet]).getWarp() - 1);
((Ship)space[X][Y]).setProjectile(((Ship)space[X][Y]).getProjectile() - 1);
if(((Ship)space[X][Y + meet]).getShield() == 0 || ((Ship)space[X][Y + meet]).getWarp() == 0){
((Ship)space[X][Y + meet]).isDestroyed = true;
return;
}
}
if(((Ship)space[X][Y + meet]).getProjectile() != 0){
((Ship)space[X][Y]).setShield(((Ship)space[X][Y]).getShield() - 1);
((Ship)space[X][Y]).setWarp(((Ship)space[X][Y]).getWarp() - 1);
((Ship)space[X][Y + meet]).setProjectile(((Ship)space[X][Y + meet]).getProjectile() - 1);
if(((Ship)space[X][Y]).getShield() == 0 || ((Ship)space[X][Y]).getWarp() == 0){
this.isDestroyed = true;
return;
}
}
if(((Ship)space[X][Y]).getProjectile() == 0 && ((Ship)space[X][Y + meet]).getProjectile() == 0)
return;
}
}
To me you shouldn't do Thread.sleep() since it doesn't release any resources it grabs. Either schedule your task using ScheduledExecutorService or do wait() and yield() on an object monitor.
Your sleep is outside of your while(true) block, so instead of sleeping for a second every loop, you sleep once and then go into a tight loop.
Put the sleep at the end of the while(true) block, so you sleep once for every iteration of the loop. Ideally it should be just after the release of the synchronization on the space array.
Actually, full array scanning is far from ideal on finding items. Might want to look into keeping lists of items. Just to get an idea, a 1000x1000 array that has 20 items in it (space is big and mostly empty) will take 1,000,000 checks as you pass over the array, but if you reorganize your checks to be base on the items, you could probably get away with just 1000 or less checks.
For example, a list of ships:
for (Ship ship : ships) {
if (!ship.engaged()) {
ship.scanForEnemies();
}
if (ship.detectEnemies()) {
ship.attack();
}
}
might only have to loop through a dozen or fewer ships, checking a few hundred locations. If you are wondering how the above code works, in my example, the ship would have been constructed with a space array, that it kept a reference to.