Java Threads: Using sleep and interrupt rather than wait and notifyAll - java

Scenario - Trying to achieve the result with sleep() and interrupt(); which
would have been otherwise done by wait() and notifyAll()
Question - I know this way is not preferred. Can you guys please let me know what is wrong in doing like this in this below
scenario.
One reason is notifyAll() notify all threads looking for the lock on that object. But with interrupt()
we have the invoke interrupt on each waiting thread explicitly.
Other reason is that a different thread cannot change the object state. Here the initial thread itself make
food=true on catching an InterruptedException. But what is wrong with that?
/**
* Objective of this program:
*
* I was thinking, why can't we achieve the guarded block with Sleep and Interrupt,
* why only with wait and notify..
*
* Wait releases lock; while Sleep does not . But both suspend the execution.
* So if you are synchronizing on the object, then we cannot have the second thread
* to modify the object state due the lock on the object, and the second thread cannot acquire it.
*
* So I did a explicit interrupt on the first thread.
*
*/
/**
*
* One person ask if he has something to eat polling the "food" variable.
* Another person updates the shared variable food.
*
* food = true means the first person can start eating. food = false means he
* has to wait and poll the value until food is available(food = true). This is
* not a producer-consumer problem.
*
*/
public class _17GuardedBlockWithSleep_Interrupt_Badcase {
static class Person {
volatile boolean food;
public boolean isFood() {
return food;
}
public void setFood(boolean food) {
this.food = food;
}
String name;
Person(String name) {
this.name = name;
}
/*
* Sloppy/Bad way of implementation making it pause execution until it
* gets interrupted. An interruption alone does not mean food is
* available. May be interrupt was called by someone else who does not
* provide food. So check the condition too.
*
* Through sleep(), the execution is paused. CPU is free to take other
* tasks, The lock on object is NOT released so other threads CANNOT
* acquire the lock on the object.
*/
// Guarded Block
public synchronized void eatFood() {
while (!isFood()) {
// food is currently unavailable. I'm waiting..
try {
/**
* Ideally we do wait() and notifyAll() in such a scenario. I am
* trying with Sleep and Interrupt.
*/
Thread.sleep(1000000000);
} catch (InterruptedException e) {
this.setFood(true);// it's not some other thread that provide food. it's itself!
System.out.println("eatFood() caught InterruptedException");
// e.printStackTrace();
}
}
// if control comes here, then it means food is available
System.out.println("got the food.. yummyy..thanks!");
}
public synchronized void provideFood(Thread t) {
this.setFood(true); // this refers to current object. In this case, the
// 'kuttappan' object
// interrupt the first thread
t.interrupt();
}
}
public static void main(String[] args) {
final Person kuttappan = new Person("Kuttappan");
Runnable runnable1 = new Runnable() {
#Override
public void run() {
/*
* if kuttappan is not already defined as final, you get an error
* "Cannot refer to a non-final variable kuttappan inside an inner class defined in a different method"
*/
kuttappan.eatFood();
/*
* thread will try to acquire the lock on 'kuttappan' object when it
* invokes the synchronized method.
*/
}
};
final Thread t = new Thread(runnable1, "thread1");
t.start();
// someone is needed to make the food available for kuttappan.
new Thread(new Runnable() {
#Override
public void run() {
try {
Thread.sleep(5000); // 5 seconds
t.interrupt(); // MY IMPORTANT LINE
// kuttappan.provideFood(t);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
}
/**
* OUTPUT:
*
* Observe the line commented as "MY IMPORTANT LINE"
*
* If you do 'kuttappan.provideFood(t);' then the program Keeps on running. no
* output, because
*
* The second thread cannot get into provideFood() of kuttappan object because
* the first thread has not released the lock on the object!
*
* But if you do t.interrupt(); the thread is interrupted and the program
* behaves as expected.
*/

From here: Difference between wait() and sleep()
"Sleeping a Thread does not release the locks it holds, while waiting releases the lock on the object that wait() is called on."
So in your case it appears that if there is no food available it's impossible for another thread to go in and make food available.
It also appears that even if you call t.interrupt(), the first thread will just see that there isn't any food, so it'll sleep again. I could very well be interpreting this incorrectly though... working on this...
Never mind, I misread part of your code. I think part of the problem is that you rely on the original thread itself to do the work that the second thread should have done. So really you're not doing much better than having a single thread add food then consume it...

Its a poor choice because you are counting on one thread catching an interrupted exception every time. Exceptions are a high overhead mechanism for IPC. There may be more reasons but this is enough to get it yanked out of production code.

I think in your scenario producer thread should always have reference to consumer thread in order to interrupt() it and give it possibility to process "event".
If you use wait()/notify() you do not need threads to know each other, all you need is a synchronization point - object that you wait/notify on. Also you can share this object with as many threads as you want. So at the end producer thread does not care who exactly waits for the resource, it only needs to send signal that resource is available.

Related

Free all waiting threads

I'm writing this class that simulates a barrier point. When a thread reaches this barrier point it cannot proceed until the other threads have also reached this point. I am using a counter to keep track of the number of threads that have arrived at this point. Assume that the class is expecting N+1 threads, but is only given N threads. In this case the program will keep all the threads waiting because it thinks that there is still one more thread to arrive.
I want to write a method that will allow me to free all of the waiting threads regardless of whether or not the program thinks there is still more threads to arrive at the barrier point.
My program to wait for all threads,
public volatile int count;
public static boolean cycle = false;
public static Lock lock = new ReentrantLock();
public static Condition cv = lock.newCondition();
public void barrier() throws InterruptedException {
boolean cycle;
System.out.println("lock");
lock.lock();
try {
cycle = this.cycle;
if (--this.count == 0) {
System.out.println("releasing all threads");
this.cycle = !this.cycle;
cv.signalAll();
} else {
while (cycle == this.cycle) {
System.out.println("waiting at barrier");
cv.await(); // Line 20
}
}
} finally {
System.out.println("unlock");
lock.unlock();
}
}
I was thinking I could simply create a method that calls the signalAll() method and all the threads would be free. However, a problem I am having is that if the program is expecting more threads it will maintain a lock because it will be waiting at line 20.
Is there a way to get around this lock? How should I approach this problem?
Better idea - use standard java.util.concurrent primitive - CyclicBarrier with method 'reset':
/**
* Resets the barrier to its initial state. If any parties are
* currently waiting at the barrier, they will return with a
* {#link BrokenBarrierException}. Note that resets <em>after</em>
* a breakage has occurred for other reasons can be complicated to
* carry out; threads need to re-synchronize in some other way,
* and choose one to perform the reset. It may be preferable to
* instead create a new barrier for subsequent use.
*/
public void reset()

Program gets halted: wait() and notify()

I am trying to achieve this: Created two different threads, one prints odd numbers, one prints even numbers. Once one thread prints a number, it has to wait for the other thread and so on, that is one-after-other.
To achieve this, i am using synchronized block along with wait() and notify().
I am creating a class whose's object will be used to pass to synchronized block in both the threads.
Here is the code:
--> This is used object which will be passed to synchronized block.
package com.vipin.multithread.variousdemos;
public class SyncObject {
public SyncObject () {
}
}
Odd Thread:
package com.vipin.multithread.variousdemos;
public class OddThread implements Runnable {
private Thread t;
int index=0;
SyncObject so=null;
int odd_nums[] = {1,3,5,7,9};
public OddThread(SyncObject so) {
t = new Thread(this,"Odd Thread");
this.so = so;
t.start();
}
public Thread getThreadInstance() {
return t;
}
#Override
public void run() {
while (true) {
synchronized(so) {
System.out.println("Odd num is --->" + odd_nums[index]);
try {
so.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
index++;
so.notify();
if(index>=5) {
return;
}
}
}
}
}
Even Thread: UPDATE
package com.vipin.multithread.variousdemos;
public class EvenThread implements Runnable {
private Thread t;
int index=0;
SyncObject so=null;
int even_nums[] = {2,4,6,8,10};
public EvenThread(SyncObject so) {
t = new Thread(this, "Even thread");
this.so = so;
t.start();
}
public Thread getThreadInstance() {
return t;
}
#Override
public void run() {
while(true) {
synchronized(so) {
System.out.println("Even num is --->" + even_nums[index]);
so.notify(); <-- Here we are notifying.
try {
so.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
index++;
//so.notify(); <-- commented out.
if(index>=5) {
break;
}
}
}
}
}
Main Application:
package com.vipin.multithread.variousdemos;
public class EvenOddDemo {
public static void main(String[] args) throws InterruptedException {
SyncObject so = new SyncObject();
OddThread ot = new OddThread(so);
EvenThread et = new EvenThread(so);
System.out.println("\nIn main thread");
Thread.sleep(1000000000);
System.out.println("Exiting main thread...");
}
}
---> As seen in the code, I am creating two threads to print even and odd numbers. I am using synchronized block, and passing object of type ==> SyncObject.
SyncObject I am passing as argument to these different threads in main.
However, this programs halts, i.e stuck only first statement gets executed, and then it waits forever:
Here is the output:
Odd num is --->1
In main thread
Even num is --->2
I am not able to understand why this program waits for ever, I am using SAME object on which we are invoking synchronized(), wait() and notify(). As per my understanding, it should work, not sure why this is not working.
Any clues as to why this is waiting forever.
UPDATE:
I did some changes in the code, UPDATE and it works fine.
I still have some doubt. Does notify() be called by the thread even if it has not locked the monitor, like in my case after i updated the code.
Sequence of events:
Odd thread gets executed first, then it calls wait() <-- it releases the monitor and now in sleep mode.
Even thread runs, prints msg, and calls notify() <-- here i am not having clear understanding.
When Even thread calls notify(), at that point it has the monitor, so when it calls notify(), does is still own the monitor?
Now, after Even thread calls notify(), then Odd thread gets notified, and hence it starts execution from the point it was sleeping. It is doing some execution and calls notify(), at that points I presume Odd thread is NOT owning the monitor, it calls notify(). So, my question is, does notify() work same whether or not the thread owns the monitor?
It is only when one do the code, one really understands this. I read book and i felt i understood everything, and seems i am back to square one!
The problem here is simply that both threads go straight into wait. Thread 1 gets so, prints value then waits. Thread 2 then gets so, prints value then waits. So both are sleeping away, since nobody is there to notify them. So, a simple fix would be to do so.notify(), right before so.wait(). Then they're not infinitely waiting.
EDIT
Odd thread starts, executes & then waits. Then even thread starts, executes, notifies & then waits. Even thread holds the lock over the monitor until it goes into wait.
When the even thread called on notify, the odd thread awakens & polls for the lock. Once the even thread goes into wait (& releases the lock), then the odd thread can obtain the lock.
If the even thread had not called on notify, then the odd thread would continue to sleep. The even thread would have gone to wait & released the lock. No thread is polling or attempting to obtain the lock, hence the program remains in the suspended state.
The documentation also provides a similar explanation. I hope that clears your doubts.

How does wait and notify work?

I need to know how wait() and notify() works exactly? I couldn't achieve its working by using wait() and notify() as such. Instead if I use a while() loop for wait, it works properly. How is it so? Why can't I use just wait() and notify() simply?
have you read the documentation of the wait-notify functions ?
anyway, for the best way to achieve a wait-notify mechanism, use something like this (based on this website) :
public class WaitNotifier {
private final Object monitoredObject = new Object();
private boolean wasSignalled = false;
/**
* waits till another thread has called doNotify (or if this thread was interrupted), or don't if was already
* notified before
*/
public void doWait() {
synchronized (monitoredObject) {
while (!wasSignalled) {
try {
monitoredObject.wait();
} catch (final InterruptedException e) {
break;
}
}
wasSignalled = false;
}
}
/**
* notifies the waiting thread . will notify it even if it's not waiting yet
*/
public void doNotify() {
synchronized (monitoredObject) {
wasSignalled = true;
monitoredObject.notify();
}
}
}
do note, that each instance of this class should be used only once, so you might want to change it if you need to use it multiple times.
wait() and notify() are used in synchronized block while using threads to suspend and resume where left off.
Wait immediately looses the lock, whereas Nofity will leave the lock only when the ending bracket is encountered.
You can also refer this sample example:
public class MyThread implements Runnable {
public synchronized void waitTest() {
System.out.println("Before Wait");
wait();
System.out.println("After Wait");
}
public synchronized void notifyTest() {
System.out.println("Before Notify");
notify();
System.out.println("After Notify");
}
}
public class Test {
public static void main(String[] args) {
Thread t = new Thread(new MyThread());
t.start();
}
}
I think you are asking why does it work with while loop and does not without.
The answer is when your program calls wait() the operation system suspends your thread and activates (starts) another, and there will happen so called context switch.When OS suspend a thread it needs to save some "meta data" about your thread in order to be able to resume that thread later, PC register is what will answer your question.Basically PC (Program Counter) is a pointer to next instruction which the thread should do or is going to do, after being resumed a thread uses it to understand which instruction it was going to do when OS suspended him, and continues by that instruction (in this case, if you want to look at it by the means of Java program, the next instruction will be the next line after call to wait()).As written in "Java Concurrency in Practice"
Every call to wait is implicitly associated with a specific condition predicate. When calling wait regarding a particular
condition predicate, the caller must already hold the lock associated with the condition queue, and that lock must also
guard the state variables from which the condition predicate is composed.
Because your thread waits because some condition was not met (it should be) after returning to the method that it was suspended in, it needs to recheck that condition to see is it met yet.If condition is met it will not wait anymore, if it's not met it will call wait() again ( as it is in while loop).The important thing to know here is
PC (Program Counter) concept
and
The fact that a Thread that calls wait() on your method will not exit the method -> wait -> get resumed again -> call the method again, instead it will wait -> get resumed again -> continue from the point (instruction/line) where it was suspended (called wait())

threads reagarding notification

I was going through threads and I read that ..The notify() method is used to send a signal to one and only one of the threads that are waiting in that same object's waiting pool.
The method notifyAll() works in the same way as notify(), only it sends the signal to all of the threads waiting on the object.
Now my query is that if Lets say I have 5 threads waiting and through Notify() , i want to send to notification to thread 3 only, what logic should be there that notification is sent to thread 3 only ..!!
You can't directly do this with wait and notify. You'd have to set a flag somewhere, have the code in the thread check it and go back to waiting if it's the wrong thread, and then call notifyAll.
Note that if you have to deal with this, it might be a sign that you should restructure your code. If you need to be able to notify each individual thread, you should probably make each of them wait on a different object.
wait-notify is rather a low level mechanism to indicate to other threads that an event (being expected occured). Example of this is producer/consumer mechanism.
It is not a mechanism for threads to communicate to each other.
If you need something like that you are looking in the wrong way.
The following code starts up five threads and sets the third one a flag which tells it that it is the only to continue. Then all of the threads that are waiting on the same lock object lock are notified (woken-up), but only the one selected continues. Be careful, writing multi-threaded applications is not easy at all (proper synchronization, handling the spurious wake-ups, etc.) You should not need to wake up only one particular thread from the group as this points to an incorrect problem decomposition. Anyway, here you go...
package test;
public class Main {
public static void main(String[] args) {
Main m = new Main();
m.start(5);
}
private void start(int n) {
MyThread[] threads = new MyThread[n];
for (int i = 0; i < n; i++) {
threads[i] = new MyThread();
/* set the threads as daemon ones, so that JVM could exit while they are still running */
threads[i].setDaemon(true);
threads[i].start();
}
/* wait for the threads to start */
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
/* tell only the third thread that it is able to continue */
threads[2].setCanContinue(true);
/* wake up all threads waiting on the 'lock', but only one of them is instructed to continue */
synchronized (lock) {
lock.notifyAll();
}
/* wait some time before exiting, thread two should be able to finish correctly, the others will be discarded with the end of the JVM */
for (int i = 0; i < n; i++) {
try {
threads[i].join(500);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
System.out.println("Done!");
}
/** synchronization object, i.e. a lock which makes sure that only one thread can get into "Critical Section" */
private final Object lock = new Object();
/** A simple thread to demonstrate the issue */
private final class MyThread extends Thread {
private volatile boolean canContinue;
#Override
public void run() {
System.out.println(Thread.currentThread().getName() + " going to wait...");
synchronized (lock) {
while (!canContinue) {
try {
lock.wait(1000); /* one second */
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
System.out.println(Thread.currentThread().getName() + " woken up!");
}
public void setCanContinue(boolean canContinue) {
this.canContinue = canContinue;
}
};
}
The output of the code is:
Thread-0 going to wait...
Thread-2 going to wait...
Thread-3 going to wait...
Thread-1 going to wait...
Thread-4 going to wait...
Thread-2 woken up!
Done!
So you can clearly see that only the third thread (indexed from zero) is woken up. You have to study the Java synchronization and multi-threading in more detail to understand every particular line of the code (for example, here).
I would like to help you more, but I would have to write almost a book about Java threads and that is why I just pointed out to this Java Tutorial on threads. You are right, this problematics is not easy at all, especially for beginners. So I advise you to read through the referenced tutorial and then you should be able to understand most of the code above. There is no easy way around or at least I do not know of any.

Dynamic resizing of java.util.concurrent.ThreadPoolExecutor while it has waiting tasks

I'm working with a java.util.concurrent.ThreadPoolExecutor to process a number of items in parallel. Although the threading itself works fine, at times we've run into other resource constraints due to actions happening in the threads, which made us want to dial down the number of Threads in the pool.
I'd like to know if there's a way to dial down the number of the threads while the threads are actually working. I know that you can call setMaximumPoolSize() and/or setCorePoolSize(), but these only resize the pool once threads become idle, but they don't become idle until there are no tasks waiting in the queue.
You absolutely can. Calling setCorePoolSize(int) will change the core size of the pool. Calls to this method are thread-safe and override settings provided to the constructor of ThreadPoolExecutor. If you are trimming the pool size, the remaining threads will shut-down once their current job queue is completed (if they are idle, they will shut-down immediately). If you are increasing the pool size, new threads will be allocated as soon as possible. The timeframe for the allocation of new threads is undocumented — but in the implementation, allocation of new threads is performed upon each call to the execute method.
To pair this with a runtime-tunable job-farm, you can expose this property (either by wrapper or using a dynamic MBean exporter) as a read-write JMX attribute to create a rather nice, on-the-fly tunable batch processor.
To reduce the pool size forcibly in runtime (which is your request), you must subclass the ThreadPoolExecutor and add a disruption to the beforeExecute(Thread,Runnable) method. Interrupting the thread is not a sufficient disruption, since that only interacts with wait-states and during processing the ThreadPoolExecutor task threads do not go into an interruptable state.
I recently had the same problem trying to get a thread pool to forcibly terminate before all submitted tasks are executed. To make this happen, I interrupted the thread by throwing a runtime exception only after replacing the UncaughtExceptionHandler of the thread with one that expects my specific exception and discards it.
/**
* A runtime exception used to prematurely terminate threads in this pool.
*/
static class ShutdownException
extends RuntimeException {
ShutdownException (String message) {
super(message);
}
}
/**
* This uncaught exception handler is used only as threads are entered into
* their shutdown state.
*/
static class ShutdownHandler
implements UncaughtExceptionHandler {
private UncaughtExceptionHandler handler;
/**
* Create a new shutdown handler.
*
* #param handler The original handler to deligate non-shutdown
* exceptions to.
*/
ShutdownHandler (UncaughtExceptionHandler handler) {
this.handler = handler;
}
/**
* Quietly ignore {#link ShutdownException}.
* <p>
* Do nothing if this is a ShutdownException, this is just to prevent
* logging an uncaught exception which is expected. Otherwise forward
* it to the thread group handler (which may hand it off to the default
* uncaught exception handler).
* </p>
*/
public void uncaughtException (Thread thread, Throwable throwable) {
if (!(throwable instanceof ShutdownException)) {
/* Use the original exception handler if one is available,
* otherwise use the group exception handler.
*/
if (handler != null) {
handler.uncaughtException(thread, throwable);
}
}
}
}
/**
* Configure the given job as a spring bean.
*
* <p>Given a runnable task, configure it as a prototype spring bean,
* injecting any necessary dependencices.</p>
*
* #param thread The thread the task will be executed in.
* #param job The job to configure.
*
* #throws IllegalStateException if any error occurs.
*/
protected void beforeExecute (final Thread thread, final Runnable job) {
/* If we're in shutdown, it's because spring is in singleton shutdown
* mode. This means we must not attempt to configure the bean, but
* rather we must exit immediately (prematurely, even).
*/
if (!this.isShutdown()) {
if (factory == null) {
throw new IllegalStateException(
"This class must be instantiated by spring"
);
}
factory.configureBean(job, job.getClass().getName());
}
else {
/* If we are in shutdown mode, replace the job on the queue so the
* next process will see it and it won't get dropped. Further,
* interrupt this thread so it will no longer process jobs. This
* deviates from the existing behavior of shutdown().
*/
workQueue.add(job);
thread.setUncaughtExceptionHandler(
new ShutdownHandler(thread.getUncaughtExceptionHandler())
);
/* Throwing a runtime exception is the only way to prematurely
* cause a worker thread from the TheadPoolExecutor to exit.
*/
throw new ShutdownException("Terminating thread");
}
}
In your case, you may want to create a semaphore (just for use as a threadsafe counter) which has no permits, and when shutting down threads release to it a number of permits that corresponds to the delta of the previous core pool size and the new pool size (requiring you override the setCorePoolSize(int) method). This will allow you to terminate your threads after their current task completes.
private Semaphore terminations = new Semaphore(0);
protected void beforeExecute (final Thread thread, final Runnable job) {
if (terminations.tryAcquire()) {
/* Replace this item in the queue so it may be executed by another
* thread
*/
queue.add(job);
thread.setUncaughtExceptionHandler(
new ShutdownHandler(thread.getUncaughtExceptionHandler())
);
/* Throwing a runtime exception is the only way to prematurely
* cause a worker thread from the TheadPoolExecutor to exit.
*/
throw new ShutdownException("Terminating thread");
}
}
public void setCorePoolSize (final int size) {
int delta = getActiveCount() - size;
super.setCorePoolSize(size);
if (delta > 0) {
terminations.release(delta);
}
}
This should interrupt n threads for f(n) = active - requested. If there is any problem, the ThreadPoolExecutors allocation strategy is fairly durable. It book-keeps on premature termination using a finally block which guarantees execution. For this reason, even if you terminate too many threads, they will repopulate.
As far as I can tell, this is not possible in a nice clean way.
You can implement the beforeExecute method to check some boolean value and force threads to halt temporarily. Keep in mind, they will contain a task which will not be executed until they are re-enabled.
Alternatively, you can implement afterExecute to throw a RuntimeException when you are saturated. This will effectively cause the Thread to die and since the Executor will be above the max, no new one would be created.
I don't recommend you do either. Instead, try to find some other way of controlling concurrent execution of the tasks which are causing you a problem. Possibly by executing them in a separate thread pool with a more limited number of workers.
The solution is to drain the ThreadPoolExecutor queue, set the ThreadPoolExecutor size as needed and then add back the threads, one by one, as soon as the others ends.
The method to drain the queue in the ThreadPoolExecutor class is private so you have to create it by yourself. Here is the code:
/**
* Drains the task queue into a new list. Used by shutdownNow.
* Call only while holding main lock.
*/
public static List<Runnable> drainQueue() {
List<Runnable> taskList = new ArrayList<Runnable>();
BlockingQueue<Runnable> workQueue = executor.getQueue();
workQueue.drainTo(taskList);
/*
* If the queue is a DelayQueue or any other kind of queue
* for which poll or drainTo may fail to remove some elements,
* we need to manually traverse and remove remaining tasks.
* To guarantee atomicity wrt other threads using this queue,
* we need to create a new iterator for each element removed.
*/
while (!workQueue.isEmpty()) {
Iterator<Runnable> it = workQueue.iterator();
try {
if (it.hasNext()) {
Runnable r = it.next();
if (workQueue.remove(r))
taskList.add(r);
}
} catch (ConcurrentModificationException ignore) {
}
}
return taskList;
}
Before calling this method you need to get and then release the main lock.
To do this you need to use java reflection because the field "mainLock" is private.
Again, here is the code:
private Field getMainLock() throws NoSuchFieldException {
Field mainLock = executor.getClass().getDeclaredField("mainLock");
mainLock.setAccessible(true);
return mainLock;
}
Where "executor" is your ThreadPoolExecutor.
Now you need lock/unlock methods:
public void lock() {
try {
Field mainLock = getMainLock();
Method lock = mainLock.getType().getDeclaredMethod("lock", (Class[])null);
lock.invoke(mainLock.get(executor), (Object[])null);
} catch {
...
}
}
public void unlock() {
try {
Field mainLock = getMainLock();
mainLock.setAccessible(true);
Method lock = mainLock.getType().getDeclaredMethod("unlock", (Class[])null);
lock.invoke(mainLock.get(executor), (Object[])null);
} catch {
...
}
}
Finally you can write your "setThreadsNumber" method, and it will work both increasing and decreasing the ThreadPoolExecutor size:
public void setThreadsNumber(int intValue) {
boolean increasing = intValue > executor.getPoolSize();
executor.setCorePoolSize(intValue);
executor.setMaximumPoolSize(intValue);
if(increasing){
if(drainedQueue != null && (drainedQueue.size() > 0)){
executor.submit(drainedQueue.remove(0));
}
} else {
if(drainedQueue == null){
lock();
drainedQueue = drainQueue();
unlock();
}
}
}
Note: obviously if you execute N parallel threads and the you change this number to N-1, all the N threads will continue to run. When the first thread ends no new threads will be executed. From now on the number of parallel thread will be the one you have chosen.
I was in a need for the same solution too, and it seems that in JDK8 the setCorePoolSize() and setMaximumPoolSize() do indeed produce the desired result.
I made a test case where I submit 4 tasks to the pool and they execute concurently, I shrink the pool size while they are running and submit yet another runnable that I want to be lonesome. Then I restore the pool back to its original size. Here is the test source https://gist.github.com/southerton81/96e141b8feede3fe0b8f88f679bef381
It produces the following output (thread "50" is the one that should be executed in isolation)
run:
test thread 2 enter
test thread 1 enter
test thread 3 enter
test thread 4 enter
test thread 1 exit
test thread 2 exit
test thread 3 exit
test thread 4 exit
test thread 50 enter
test thread 50 exit
test thread 1 enter
test thread 2 enter
test thread 3 enter
test thread 4 enter
test thread 1 exit
test thread 2 exit
test thread 3 exit
test thread 4 exit

Categories