Override execute() in ThreadPoolExecutor - java

I'm looking for a ThreadPoolExecutor that will block when it's task queue is full - the current Java implementation rejects new tasks if the underlying queue is full -
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
* Proceed in 3 steps:
*
* 1. If fewer than corePoolSize threads are running, try to
* start a new thread with the given command as its first
* task. The call to addWorker atomically checks runState and
* workerCount, and so prevents false alarms that would add
* threads when it shouldn't, by returning false.
*
* 2. If a task can be successfully queued, then we still need
* to double-check whether we should have added a thread
* (because existing ones died since last checking) or that
* the pool shut down since entry into this method. So we
* recheck state and if necessary roll back the enqueuing if
* stopped, or start a new thread if there are none.
*
* 3. If we cannot queue task, then we try to add a new
* thread. If it fails, we know we are shut down or saturated
* and so reject the task.
*/
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
would changing this line:
if (isRunning(c) && workQueue.offer(command)) {
TO
if (isRunning(c) && workQueue.put(command)) {
Do the trick? Am I missing something?
SOLUTION (might help the next person):
public class BlockingThreadPoolExecutor extends ThreadPoolExecutor {
private final Semaphore runLock;
public BlockingThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, int maxTasks) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
runLock = new Semaphore(maxTasks);
}
#Override
protected void beforeExecute(Thread t, Runnable r) {
runLock.acquireUninterruptibly();
}
#Override
protected void afterExecute(Runnable r, Throwable t) {
runLock.release();
}
}

Depends on the ThreadPoolExecutor state and settings because not all task submissions pass through the BlockingQueue. Usually you just want to change the RejectedExecutionHandler of the ThreadPoolExecutor to the ThreadPoolExecutor.CallerRunsPolicy which will throttle submissions. If you really want to block on submit then you should use a CompletionService and call the 'take' method when you want to block. You can also create a subclass and use a Semaphore to block the execute method. See JDK-6648211 : Need for blocking ThreadPoolExecutor for more information.

Related

ThreadPoolExecutor dynamic task execution, wait until all task completion

I have a ThreadPoolExecutor as such
ThreadPoolExecutor executor = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<>());
The tasks are executed as follows
executor.execute(task)
Now each task may also execute more tasks to the same executor and those new tasks can submit more tasks
The problem is I want the main thread to wait until all tasks are executed and then call shutdown
Is the following approach guaranteed to work? (i.e. block/wait main
thread until all tasks are completed)
while (executor.getCompletedTaskCount() < executor.getTaskCount()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
LOGGER.error("Exception in atomic Count wait thread sleep", e);
break;
}
}
}
Will this eventually break out of loop? Just by preliminary testing, I found that it works even with exceptions in thread
P.S.
I cannot use latch, because I don't know the number of tasks beforehand
nor the accepted answer here
You should probably keep the futures that get submitted.
Deque<Future<?>> futures = new ConcurrentLinkedDeque<>();
Then everytime you submit a task.
futures.add(executor.submit( runnable, "Doesn't Really Matter, but Can be Useful"));
Then in your main thread that is waiting.
while(futures.size()>0){
futures.pop().get();
}
This will offer you a guarantee that .get will not complete until a task has finished, and if more tasks are added by another task then futures will reflect the change before the original task completes.
In my opinion it will be non-deterministic to get the actual count of tasks for the reason that while the tasks are submitted the execute method is called and one of below 3 conditions may happen.
1. Task starts executing (added to Workers)
2. Task is enqueued (added to WorkQueue)
3. Task is rejected as WorkerQueue capacity,Workers capacity and resources exhaust
/**
* Executes the given task sometime in the future. The task
* may execute in a new thread or in an existing pooled thread.
*
* If the task cannot be submitted for execution, either because this
* executor has been shutdown or because its capacity has been reached,
* the task is handled by the current {#code RejectedExecutionHandler}.
*
* #param command the task to execute
* #throws RejectedExecutionException at discretion of
* {#code RejectedExecutionHandler}, if the task
* cannot be accepted for execution
* #throws NullPointerException if {#code command} is null
*/
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
* Proceed in 3 steps:
*
* 1. If fewer than corePoolSize threads are running, try to
* start a new thread with the given command as its first
* task. The call to addWorker atomically checks runState and
* workerCount, and so prevents false alarms that would add
* threads when it shouldn't, by returning false.
*
* 2. If a task can be successfully queued, then we still need
* to double-check whether we should have added a thread
* (because existing ones died since last checking) or that
* the pool shut down since entry into this method. So we
* recheck state and if necessary roll back the enqueuing if
* stopped, or start a new thread if there are none.
*
* 3. If we cannot queue task, then we try to add a new
* thread. If it fails, we know we are shut down or saturated
* and so reject the task.
*/
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
getTaskCount() and getCompletedTaskCount() methods are guarded by mainLock hence we do know if internal threads still submitting tasks to executor will be done by the time check (while (executor.getCompletedTaskCount() < executor.getTaskCount()) ) in main executes. This condition may result is false positive for a moment ending into a wrong result.
/**
* Returns the approximate total number of tasks that have ever been
* scheduled for execution. Because the states of tasks and
* threads may change dynamically during computation, the returned
* value is only an approximation.
*
* #return the number of tasks
*/
public long getTaskCount() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
long n = completedTaskCount;
for (Worker w : workers) {
n += w.completedTasks;
if (w.isLocked())
++n;
}
return n + workQueue.size();
} finally {
mainLock.unlock();
}
}
/**
* Returns the approximate total number of tasks that have
* completed execution. Because the states of tasks and threads
* may change dynamically during computation, the returned value
* is only an approximation, but one that does not ever decrease
* across successive calls.
*
* #return the number of tasks
*/
public long getCompletedTaskCount() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
long n = completedTaskCount;
for (Worker w : workers)
n += w.completedTasks;
return n;
} finally {
mainLock.unlock();
}
}
**Code Snippets used here are from JDK 1.8 222
The methods used to get the completed count and submitted count i.e. executor.getCompletedTaskCount() & executor.getTaskCount() do not always provide a 100% accurate count as per the Java (8) docs, so the approach may not work always.
public long getTaskCount()
Returns the approximate total number of tasks that have ever been
scheduled for execution. Because the states of tasks and threads may
change dynamically during computation, the returned value is only an
approximation.
public long getCompletedTaskCount()
Returns the approximate total number of tasks that have completed
execution. Because the states of tasks and threads may change
dynamically during computation, the returned value is only an
approximation, but one that does not ever decrease across successive
calls.

Java ThreadPoolExecutor don't create new threads

I have a servlet in AEM (Adobe Experience Manager) that create a new thread per request. I use a Apache Sling threadpool to manage the threads. All is ok, but if the servlet receives haundreds request in a few seconds the thread is not created and the threadpool is converted in useless. I have to restart the AEM instance to the threadpool The threadpool uses a queue without limit with a core pool of ten elements. The configuration is the next:
ThreadPool configuration
Debuging the java.util.concurrent.ThreadPoolExecutor class, my code enter into the third "if" and then not enter in the if neither the else, so, the thread is not created.
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
* Proceed in 3 steps:
*
* 1. If fewer than corePoolSize threads are running, try to
* start a new thread with the given command as its first
* task. The call to addWorker atomically checks runState and
* workerCount, and so prevents false alarms that would add
* threads when it shouldn't, by returning false.
*
* 2. If a task can be successfully queued, then we still need
* to double-check whether we should have added a thread
* (because existing ones died since last checking) or that
* the pool shut down since entry into this method. So we
* recheck state and if necessary roll back the enqueuing if
* stopped, or start a new thread if there are none.
*
* 3. If we cannot queue task, then we try to add a new
* thread. If it fails, we know we are shut down or saturated
* and so reject the task.
*/
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
I read the documentation but not understand why this occurs.

Detect when idle ThreadPoolExecutor thread is killed

I am using ThreadPoolExecutor to manage the number of threads, I can catch the event of creating a new Thread for ThreadPool via ThreadFactory->newThread()
But I do now know how to catch the event of killing Thread which stays idle for 2minutes as following configuration.
I hae searched a listener method but could not find.
public abstract class ThreadPoolEventProcessor<E> implements ThreadFactory{
private BlockingQueue<Runnable> taskQueue;
private ThreadPoolExecutor executor;
protected ThreadPoolEventProcessor(int coreThreadSize, int maxQueueSize) {
taskQueue = new LinkedBlockingQueue<Runnable>(maxQueueSize);
executor = new ThreadPoolExecutor(coreThreadSize, coreThreadSize * 5, 2L, TimeUnit.MINUTES, taskQueue,this);
executor.prestartAllCoreThreads();
}
public Thread newThread(Runnable r) {
return new Thread(r, getWorkerName());
}
The ThreadPoolExecutor does not kill threads. It will retrieve new threads from the ThreadFactory and have them run a Worker. All this worker does is loop, attempting to retrieve a Runnable from an underlying BlockingQueue.
If it gets one, it invokes run on it.
If the allowCoreThreadTimeOut is true and you have more workers than the core amount, then the keepAliveTime value is used to poll that underlying BlockingQueue. If the poll returns null, then the worker is (potentially) removed. Some extra cleanup happens and the various method invocations are popped from the stack as the methods return, until eventually the Worker#run() method terminates and the containing thread finishes.
Nowhere in that flow does ThreadPoolExecutor offer any hooks for notifications.
You can poll ThreadPoolExecutor#getPoolSize() and ThreadPoolExecutor#getLargestPoolSize() for information periodically.
In ThreadPoolExecutor class there is a set of Workers, which are runnable classes ran by Threads in the pool.
When a worker is done workerDone call back executes. And there you see a tryTerminate method being called. That is the method deciding if to terminate thread or not. You should be able to debug at that point
/**
* Performs bookkeeping for an exiting worker thread.
* #param w the worker
*/
void workerDone(Worker w) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
completedTaskCount += w.completedTasks;
workers.remove(w);
if (--poolSize == 0)
tryTerminate();
} finally {
mainLock.unlock();
}
}
/* Termination support. */
/**
* Transitions to TERMINATED state if either (SHUTDOWN and pool
* and queue empty) or (STOP and pool empty), otherwise unless
* stopped, ensuring that there is at least one live thread to
* handle queued tasks.
*
* This method is called from the three places in which
* termination can occur: in workerDone on exit of the last thread
* after pool has been shut down, or directly within calls to
* shutdown or shutdownNow, if there are no live threads.
*/
private void tryTerminate() {
if (poolSize == 0) {
int state = runState;
if (state < STOP && !workQueue.isEmpty()) {
state = RUNNING; // disable termination check below
addThread(null);
}
if (state == STOP || state == SHUTDOWN) {
runState = TERMINATED;
termination.signalAll();
terminated();
}
}
}

ThreadPoolExecutor and the queue

I thought that using ThreadPoolExecutor we can submit Runnables to be executed either in the BlockingQueue passed in the constructor or using the execute method.
Also my understanding was that if a task is available it will be executed.
What I don't understand is the following:
public class MyThreadPoolExecutor {
private static ThreadPoolExecutor executor;
public MyThreadPoolExecutor(int min, int max, int idleTime, BlockingQueue<Runnable> queue){
executor = new ThreadPoolExecutor(min, max, 10, TimeUnit.MINUTES, queue);
//executor.prestartAllCoreThreads();
}
public static void main(String[] main){
BlockingQueue<Runnable> q = new LinkedBlockingQueue<Runnable>();
final String[] names = {"A","B","C","D","E","F"};
for(int i = 0; i < names.length; i++){
final int j = i;
q.add(new Runnable() {
#Override
public void run() {
System.out.println("Hi "+ names[j]);
}
});
}
new MyThreadPoolExecutor(10, 20, 1, q);
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
/*executor.execute(new Runnable() {
#Override
public void run() {
System.out.println("++++++++++++++");
}
}); */
for(int i = 0; i < 100; i++){
final int j = i;
q.add(new Runnable() {
#Override
public void run() {
System.out.println("Hi "+ j);
}
});
}
}
}
This code does not do absolutely anything unless I either uncomment the executor.prestartAllCoreThreads(); in the constructor OR I call execute of the runnable that prints System.out.println("++++++++++++++"); (it is also commented out).
Why?
Quote (my emphasis):
By default, even core threads are initially created and started only
when new tasks arrive, but this can be overridden dynamically using
method prestartCoreThread() or prestartAllCoreThreads(). You probably
want to prestart threads if you construct the pool with a non-empty
queue.
Ok. So my queue is not empty. But I create the executor, I do sleep and then I add new Runnables to the queue (in the loop to 100).
Doesn't this loop count as new tasks arrive?
Why doesn't it work and I have to either prestart or explicitely call execute?
Worker threads are spawned as tasks arrive by execute, and these are the ones that interact with the underlying work queue. You need to prestart the workers if you begin with a non-empty work queue. See the implementation in OpenJDK 7.
I repeat, the workers are the ones that interact with the work queue. They are only spawned on demand when passed via execute. (or the layers above it, e.g. invokeAll, submit, etc.) If they are not started, it will not matter how much work you add to the queue, since there is nothing checking it as there are no workers started.
ThreadPoolExecutor does not spawn worker threads until necessary or if you pre-empt their creation by the methods prestartAllCoreThreads and prestartCoreThread. If there are no workers started, then there is no way any of the work in your queue is going to be done.
The reason adding an initial execute works is that it forces the creation of a sole core worker thread, which then can begin processing the work from your queue. You could also call prestartCoreThread and receive similar behavior. If you want to start all the workers, you must call prestartAllCoreThreads or submit that number of tasks via execute.
See the code for execute below.
/**
* Executes the given task sometime in the future. The task
* may execute in a new thread or in an existing pooled thread.
*
* If the task cannot be submitted for execution, either because this
* executor has been shutdown or because its capacity has been reached,
* the task is handled by the current {#code RejectedExecutionHandler}.
*
* #param command the task to execute
* #throws RejectedExecutionException at discretion of
* {#code RejectedExecutionHandler}, if the task
* cannot be accepted for execution
* #throws NullPointerException if {#code command} is null
*/
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
* Proceed in 3 steps:
*
* 1. If fewer than corePoolSize threads are running, try to
* start a new thread with the given command as its first
* task. The call to addWorker atomically checks runState and
* workerCount, and so prevents false alarms that would add
* threads when it shouldn't, by returning false.
*
* 2. If a task can be successfully queued, then we still need
* to double-check whether we should have added a thread
* (because existing ones died since last checking) or that
* the pool shut down since entry into this method. So we
* recheck state and if necessary roll back the enqueuing if
* stopped, or start a new thread if there are none.
*
* 3. If we cannot queue task, then we try to add a new
* thread. If it fails, we know we are shut down or saturated
* and so reject the task.
*/
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
A BlockingQueue is not a magic thread dispatcher. If you submit Runnable objects to the queue and there are no running threads to consume those tasks, they of course will not be executed. The execute method on the other hand will automatically dispatch threads according to the thread pool configuration if it needs to. If you pre-start all of the core threads, there will be threads there to consume tasks from the queue.

Java: How can a thread wait on multiple objects?

A thread can use Object.wait() to block until another thread calls notify() or notifyAll() on that object.
But what if a thread wants to wait until one of multiple objects is signaled? For example, my thread must wait until either a) bytes become available to read from an InputStream or b) an item is added to an ArrayList.
How can the thread wait for either of these events to occur?
EDIT
This question deals with waiting for multiple threads to complete -- my case involves a thread waiting for one of many objects to be singnaled.
You are in for a world of pain. Use a higher level abstraction, such as a blocking message queue, from which the thread can consume messages such as 'more bytes available' or 'item added'.
They could all use the same mutex. You consumer is waiting on that mutex, the both other notify on that mutex when the first can proceed.
A thread cannot wait on more than one object at a time.
The wait() and notify() methods are object-specific. The wait() method suspends the current thread of execution, and tells the object to keep track of the suspended thread. The notify() method tells the object to wake up the suspended threads that it is currently keeping track of.
Useful link : Can a thread call wait() on two locks at once in Java (6) ?
Little late, but it's a very interesting question!
It would seems that you can indeed wait for multiple conditions, with the same performance, and no extra threads; It's just a matter of defining the problem! I took the time to write a more detailed explanation within the commits of the code bellow. By request I will extract the abstraction:
So in fact waiting on multiple objects, is the same as waiting on multiple conditions. But the next step is to merge your sub-conditions into a -net- condition a -single condition-. And when any component of the condition would cause it to become true you flip a boolean, and notify the lock (like any other wait-notify condition).
My approach:
For any condition, it can only result in two values (true and false). How that value is produced is irrelevant. In your case your "functional condition" is when either one of two values is true: (value_a || value_b). I call this "functional condition" the "Nexus-Point". If you apply the perspective that any complex condition -no matter how complex-, always yields a simple result (true or false), then what you're really asking for is "What will cause my net condition to become true?" (Assuming the logic is "Wait until true"). Thus, when a thread causes a component of your condition to become true (setting value_a, or value_b to true, in your case), and you know it'll cause your desired -net- condition to be met, then you can simplify your approach to a classical ( in that it flips a single boolean-flag, and releases a lock). With this concept, you can apply a object-ordinate approach to help aid the clarity of your overall logic:
import java.util.HashSet;
import java.util.Set;
/**
* The concept is that all control flow operation converge
* to a single value: true or false. In the case of N
* components in which create the resulting value, the
* theory is the same. So I believe this is a matter of
* perspective and permitting 'simple complexity'. for example:
*
* given the statement:
* while(condition_a || condition_b || ...) { ... }
*
* you could think of it as:
* let C = the boolean -resulting- value of (condition_a || condition_b || ...),
* so C = (condition_a || condition_b || ...);
*
* Now if we were to we-write the statement, in lamest-terms:
* while(C) { ... }
*
* Now if you recognise this form, you'll notice its just the standard
* syntax for any control-flow statement?
*
* while(condition_is_not_met) {
* synchronized (lock_for_condition) {
* lock_for_condition.wait();
* }
* }
*
* So in theory, even if the said condition was evolved from some
* complex form, it should be treated as nothing more then if it
* was in the simplest form. So whenever a component of the condition,
* in which cause the net-condition (resulting value of the complex
* condition) to be met, you would simply flip the boolean and notify
* a lock to un-park whoever is waiting on it. Just like any standard
* fashion.
*
* So thinking ahead, if you were to think of your given condition as a
* function whos result is true or false, and takes the parameters of the states
* in which its comprised of ( f(...) = (state_a || state_b && state_c), for example )
* then you would recognize "If I enter this state, in which this I know would
* cause that condition/lock to become true, I should just flip the switch switch,
* and notify".
*
* So in your example, your 'functional condition' is:
* while(!state_a && !state_b) {
* wait until state a or state b is false ....
* }
*
* So armed with this mindset, using a simple/assertive form,
* you would recognize that the overall question:
* -> What would cause my condition to be true? : if state_a is true OR state_b is true
* Ok... So, that means: When state_a or state_b turn true, my overall condition is met!
* So... I can just simplify this thing:
*
* boolean net_condition = ...
* final Object lock = new Lock();
*
* void await() {
* synchronized(lock) {
* while(!net_condition) {
* lock.wait();
* }
* }
* }
*
* Almighty, so whenever I turn state_a true, I should just flip and notify
* the net_condition!
*
*
*
* Now for a more expanded form of the SAME THING, just more direct and clear:
*
* #author Jamie Meisch
*/
public class Main {
/**
*
* The equivalent if one was to "Wait for one of many condition/lock to
* be notify me when met" :
*
* synchronized(lock_a,lock_b,lock_c) {
* while(!condition_a || !condition_b || !condition_c) {
* condition_a.wait();
* condition_b.wait();
* condition_c.wait();
* }
* }
*
*/
public static void main(String... args) {
OrNexusLock lock = new OrNexusLock();
// The workers register themselves as their own variable as part of the overall condition,
// in which is defined by the OrNuxusLock custom-implement. Which will be true if any of
// the given variables are true
SpinningWarrior warrior_a = new SpinningWarrior(lock,1000,5);
SpinningWarrior warrior_b = new SpinningWarrior(lock,1000,20);
SpinningWarrior warrior_c = new SpinningWarrior(lock,1000,50);
new Thread(warrior_a).start();
new Thread(warrior_b).start();
new Thread(warrior_c).start();
// So... if any one of these guys reaches 1000, stop waiting:
// ^ As defined by our implement within the OrNexusLock
try {
System.out.println("Waiting for one of these guys to be done, or two, or all! does not matter, whoever comes first");
lock.await();
System.out.println("WIN: " + warrior_a.value() + ":" + warrior_b.value() + ":" + warrior_c.value());
} catch (InterruptedException ignored) {
}
}
// For those not using Java 8 :)
public interface Condition {
boolean value();
}
/**
* A variable in which the net locks 'condition function'
* uses to determine its overall -net- state.
*/
public static class Variable {
private final Object lock;
private final Condition con;
private Variable(Object lock, Condition con) {
this.lock = lock;
this.con = con;
}
public boolean value() {
return con.value();
}
//When the value of the condition changes, this should be called
public void valueChanged() {
synchronized (lock) {
lock.notifyAll();
}
}
}
/**
*
* The lock has a custom function in which it derives its resulting
* -overall- state (met, or not met). The form of the function does
* not matter, but it only has boolean variables to work from. The
* conditions are in their abstract form (a boolean value, how ever
* that sub-condition is met). It's important to retain the theory
* that complex conditions yeild a simple result. So expressing a
* complex statement such as ( field * 5 > 20 ) results in a simple
* true or false value condition/variable is what this approach is
* about. Also by centerializing the overal logic, its much more
* clear then the raw -simplest- form (listed above), and just
* as fast!
*/
public static abstract class NexusLock {
private final Object lock;
public NexusLock() {
lock = new Object();
}
//Any complex condition you can fathom!
//Plus I prefer it be consolidated into a nexus point,
// and not asserted by assertive wake-ups
protected abstract boolean stateFunction();
protected Variable newVariable(Condition condition) {
return new Variable(lock, condition);
}
//Wait for the overall condition to be met
public void await() throws InterruptedException {
synchronized (lock) {
while (!stateFunction()) {
lock.wait();
}
}
}
}
// A implement in which any variable must be true
public static class OrNexusLock extends NexusLock {
private final Set<Variable> vars = new HashSet<>();
public OrNexusLock() {
}
public Variable newVar(Condition con) {
Variable var = newVariable(con);
vars.add(var); //register it as a general component of or net condition // We should notify the thread since our functional-condition has changed/evolved:
synchronized (lock) { lock.notifyAll(); }
return var;
}
#Override
public boolean stateFunction() { //Our condition for this lock
// if any variable is true: if(var_a || var_b || var_c || ...)
for(Variable var : vars) {
if(var.value() == true) return true;
}
return false;
}
}
//increments a value with delay, the condition is met when the provided count is reached
private static class SpinningWarrior implements Runnable, Condition {
private final int count;
private final long delay;
private final Variable var;
private int tick = 0;
public SpinningWarrior(OrNexusLock lock, int count, long delay) {
this.var = lock.newVar(this);
this.count = count; //What to count to?
this.delay = delay;
}
#Override
public void run() {
while (state_value==false) { //We're still counting up!
tick++;
chkState();
try {
Thread.sleep(delay);
} catch (InterruptedException ignored) {
break;
}
}
}
/**
* Though redundant value-change-notification are OK,
* its best to prevent them. As such its made clear to
* that we will ever change state once.
*/
private boolean state_value = false;
private void chkState() {
if(state_value ==true) return;
if(tick >= count) {
state_value = true;
var.valueChanged(); //Our value has changed
}
}
#Override
public boolean value() {
return state_value; //We could compute our condition in here, but for example sake.
}
}
}
It appears that in your case you're waiting for "notifications" from two different sources. You may not have to "wait" (as in normal java synchronized(object) object.wait()) on those two objects per se, but have them both talk to a queue or what not (as the other answers mention, some blocking collection like LinkedBlockingQueue).
If you really want to "wait" on two different java objects, you might be able to do so by applying some of the principles from this answer: https://stackoverflow.com/a/31885029/32453 (basically new up a thread each to do a wait on each of the objects you're waiting for, have them notify the main thread when the object itself is notified) but it might not be easy to manage the synchronized aspects.
Lock in both cases over the same object. Call in case a) or in case b) notify() on the same object.
You can wait only on one monitor. So notifiers must notify this one monitor. There is no other way in this low level synchronization.
In order handle the termination of any thread from a given set without waiting for all of them to finish, a dedicated common Object (lastExited below) can be used as monitor (wait() and notify() in synchronized blocks). Further monitors are required for ensuring that at any time at most one thread is exiting (notifyExitMutex) and at most one thread is waiting for any thread to exit (waitAnyExitMonitor); thus the wait()/notify() pairs pertain always to different blocks.
Example (all process terminations are handled in the order the threads finished):
import java.util.Random;
public class ThreadMonitor {
private final Runnable[] lastExited = { null };
private final Object notifyExitMutex = new Object();
public void startThread(final Runnable runnable) {
(new Thread(new Runnable() { public void run() {
try { runnable.run(); } catch (Throwable t) { }
synchronized (notifyExitMutex) {
synchronized (lastExited) {
while (true) {
try {
if (lastExited[0] != null) lastExited.wait();
lastExited[0] = runnable;
lastExited.notify();
return;
}
catch (InterruptedException e) { }
}
}
}
}})).start();
}
private final Object waitAnyExitMutex = new Object();
public Runnable waitAnyExit() throws InterruptedException {
synchronized (waitAnyExitMutex) {
synchronized (lastExited) {
if (lastExited[0] == null) lastExited.wait();
Runnable runnable = lastExited[0];
lastExited[0] = null;
lastExited.notify();
return runnable;
}
}
}
private static Random random = new Random();
public static void main(String[] args) throws InterruptedException {
ThreadMonitor threadMonitor = new ThreadMonitor();
int threadCount = 0;
while (threadCount != 100) {
Runnable runnable = new Runnable() { public void run() {
try { Thread.sleep(1000 + random.nextInt(100)); }
catch (InterruptedException e) { }
}};
threadMonitor.startThread(runnable);
System.err.println(runnable + " started");
threadCount++;
}
while (threadCount != 0) {
Runnable runnable = threadMonitor.waitAnyExit();
System.err.println(runnable + " exited");
threadCount--;
}
}
}

Categories