Producer and Consumer in java use notify() and wait() run 4 threads - java

Recently ,I learned about the notify and wait in Java Thread Communication, and I tried to write the classical problem of Consumer&Producer, in my code ,I actually have 4 threads ,2 are consumers and the other 2 are producers.
package producer_consumer;
class Shared {
private volatile boolean writable = true;
public Character character = 'A';
public synchronized void produceChar(Character c) {
while (!writable) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
writable = false;
character = c;
notify();
}
public synchronized void consumerChar() {
while (writable) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
writable = true;
notify();
}
}
public class PC {
public static void main(String[] args) {
Shared shared = new Shared();
class Producer extends Thread {
#Override
public synchronized void run() {
for(Character character = 'A';character<'Z';character++) {
shared.produceChar(character);
System.out.println(shared.character + " is produced");
}
}
}
class Consumer extends Thread {
#Override
public synchronized void run() {
do {
shared.consumerChar();
System.out.println(shared.character + " is consumed");
}while (shared.character!='Z');
}
}
Producer p1 = new Producer();
Producer p2 = new Producer();
Consumer c1 = new Consumer();
Consumer c2 = new Consumer();
p1.start();
p2.start();
c1.start();
c2.start();
}
}
however,when I tried to run the code , it didn't work out. I supposed it will print the letters from A to Z ,but it always get stucked. I know there must be something wrong ,but I can't figure it out by myself. Actually ,I don't konw what's wrong with it . So ,anyone will help me ? Thank you!

When your code calls notify, that tells the scheduler to pick one thread from the waitset for the lock you called notify on, and wake it up. The scheduler has no knowledge of what specific condition the threads are waiting for and there's no telling which one it will pick.
When you have multiple threads, some of which are waiting on different conditions (here the conditions are writable and not writable), then it's possible for a thread to be notified for a condition that it is not interested in. The notified thread goes back to waiting once it figures out the condition it's looking for isn't present, and no other thread receives it. That means nobody makes progress as a result of that event.
Example:
1) First producer executes, writable is true, letting it skip waiting, write s char, call notify (nobody's listening), and flip the writable flag to false.
2) Context switch to second producer, it finds writable is false so it waits.
3) At this point the scheduler could run a consumer if one is through starting, or it could switch back to the first producer.
Say it picks the producer. The first producer sees writable is still false, so it waits.
4) the first consumer runs. Writable is false so no waiting; it flips the writable flag to true and calls notify.
5) now 2 producers are waiting, the notify will wake one of them, the other is still waiting.
6) the first consumer can be picked to run again, writable is true so it waits. Now there is one producer waiting and one consumer waiting.
7) At this point the scheduler can pick either the remaining active consumer or the remaining active producer. If it picks the producer then the producer can act, then call notify. Either waiting thread could be notified. Only one can act on the notification.
One solution is to use notifyAll. That wakes up all the threads in the waitset, so if any of them are interested then they'll be notified. This is not a perfect solution for all cases; in a program with a lot of threads it can mean a lot of unproductive context switching and state transitions for most of the threads, who end up eventually going back to their wait state without having made any headway. For a small program that's not an issue, of course.
A real world solution without the downside of notifyAll is to use ReentrantLock, which allows separate conditions. That way threads wait on specific Condition objects, with the result that the notification goes only to a thread that is waiting for that specific condition.
The api doc for Condition has an example of a bounded fixed size queue that shows threads waiting on different condition objects depending on if they are producers or consumers. The conditions are not empty and not full. Threads inserting things to a full queue have to wait for the not full condition. Threads trying to take items out of an empty queue wait for the not empty condition.
Btw putting synchronized on the run method doesn't accomplish anything. Each thread is acquiring a lock on itself for the life of the thread. Locks must be shared in order to be useful. All it does is make it difficult for a thread joining on any of these to enter the waiting state.

Related

Why is notifyAll() not waking all of the threads in this example?

I'm trying to figure out how to use wait & notify, so I've written this small example with a few planes waiting for a runway to clear before they take off, the issue I'm having is that when a plane takes off, and calls notifyAll(), only one thread seems to be woken up, i.e. I expect all of the threads to report that they have been notified, but are still waiting. What actually happens is that only one thread is woken, and the rest do nothing. Why does it appear that only the one thread is woken, and how can I fix it?
class Plane extends Thread
{
Runway runway;
Plane(int id, Runway runway)
{
super(id + "");
this.runway = runway;
}
public void run()
{
runway.taxi();
runway.takeoff();
}
}
class Runway
{
boolean isFull;
Runway()
{
isFull = false;;
}
public synchronized void taxi()
{
System.out.println(Thread.currentThread().getName() + " started to taxi");
while(isFull)
{
System.out.println(Thread.currentThread().getName() + " is queued");
try
{
wait();
}
catch(InterruptedException e){}
}
isFull = true;
System.out.println(Thread.currentThread().getName() + " entering runway");
}
public synchronized void takeoff()
{
try
{
Thread.currentThread().sleep(1000);
}
catch(InterruptedException e){}
System.out.println(Thread.currentThread().getName() + " took off");
isFull = false;
notifyAll();
}
public static void main(String[] args)
{
Runway runway = new Runway();
new Plane(1, runway).start();
new Plane(2, runway).start();
new Plane(3, runway).start();
new Plane(4, runway).start();
}
}
Thanks for taking the time to help me :)
Because notifyAll() is not wakeAll(). All threads are notified, but only one gets hold of the key and is being run. All others get to waiting pull again.
Suppose you have 4 Planes that are all start()-ed one after the other.
All 4 will attempt to call taxi() followed by takeoff()
The first one will call taxi():
acquire the lock,
find isFull is false
set isFull to true
return, releasing the lock
Then one (or more) of the remaining threads may get to call taxi(). If they do, they:
acquire the lock
find isFull is false
call wait() which releases the lock
OR
block while trying to acquire the lock
In the mean time, the thread that returned from taxi() will call takeoff(). This will:
acquire the lock
sleep for 1 second,
notify any threads that were waiting
return, releasing the lock.
So how does this explain what you are seeing?
Suppose that when the first thread returned from taxi() it was immediately able to reacquire the lock and start the takeoff() call. It would then call sleep() WHILE HOLDING THE LOCK. This would prevent any other threads from starting their taxi() calls (if they hadn't already done so). Then after the sleep, it would call notifyAll(). But that would only notify the threads that were had gotten into the taxi() call and that had called wait(). Any threads that were blocked while starting the taxi() call would never see the notifications.
(Notifications are never queued for threads that are not in wait() calls.)
Is this likely? Well yes it is.
Starting a thread is a relatively expensive / time consuming process, and there is a good chance that the first thread started will get to do a lot of work before the next one gets started. The chances are that it will get all the way to the sleep call before the second one tries to call taxi().
The same pattern is likely to repeat for the remaining threads. When each thread that gets into taxi() is likely to release and then reacquire it before another thread is scheduled. (Thread scheduling is handled by the OS, and it is optimizing for efficiency rather than fairness. If you want fair scheduling, you need to use a Lock object.)
... how can a fix it?
Change your code so that you don't sleep while holding the lock. For example:
public void takeoff() {
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
// squash ...
}
System.out.println(Thread.currentThread().getName() + " took off");
synchronize (this) {
isFull = false;
notifyAll();
}
}
That's what it does. It "notifies" all the waiting threads, but only one wakes and gets the CPU. notify() picks a waiting thread based on what the underlying thread implementation selects. notifyAll() gives all the waiting threads an equal chance to compete. But either way, only one thread takes the context.

Deadlock caused by blocking methods

Say we create a thread which runs a synchronized method. This method tries to take() from an empty blocking queue. Now let a separate thread then try to put() and element onto the blocking queue while synchronized on the same object.
This causes a deadlock:
The first thread will not release the lock until an element is added to the queue.
The second thread cannot add an element until the lock is free for it to acquire.
If the two actions need to be atomic and run on separate threads, how can this be achieved without causing a deadlock?
I understand that take() and put() are thread-safe. My question is for when they are used as part of larger actions that must be atomic.
Example:
import java.util.concurrent.*;
public class DeadlockTest {
String input = "Nothing added yet!";
LinkedBlockingQueue<String> buffer = new LinkedBlockingQueue<>();
public synchronized String getFromBuffer() {
System.out.println("Trying to get input from buffer.");
try {
input = buffer.take();
} catch (InterruptedException ex) {}
System.out.println("Got:" + input + "\n");
return input;
}
public static void main(String[] args) throws InterruptedException {
DeadlockTest dl = new DeadlockTest();
new Thread(() -> {
dl.getFromBuffer();
}).start();
// Give new thread time to run.
Thread.sleep(500);
synchronized (dl) {
String message = "Hello, world!";
System.out.println("Adding: " + message);
dl.buffer.put(message);
System.out.println("Added!\n");
System.out.println("Message: " + dl.input);
}
}
}
Say we create a thread which runs a synchronized method. This method tries to take() from an empty blocking queue.
Sounds like bad design. It's usually a mistake to call any blocking methods from within a synchronized method or a synchronized statement.
If the two actions need to be atomic and run on separate threads, how can this be achieved without causing a deadlock?
Well, there's two possibilities:
In one case, the two threads are acting on different data. In that case, they should be using different locks, and they won't interfere with one another at all.
In the other case, the two threads are acting on the same data. In that case, they should lock the same lock, and one thread will have to wait for the other.
Maybe you misunderstand how a blocking queue works. If one thread is waiting to take() something from a blocking queue, that should never prevent another thread from calling put(). That would be the exact opposite of what you want.
What you want (and what you'll get from any of the blocking queue implementations in the Java standard library) is that the put() operation in the second thread will wake up the thread that's waiting to take() something from the queue.

when thread calls wait it releases the lock versus race condition

According to the basic definition of synchronized method from source - link
"When one thread is executing a synchronized method for an object, all other threads that invoke synchronized methods for the same object block (suspend execution) until the first thread is done with the object."
and I read about the wait() that it releases a lock before it sleeps. There is a confusion here if wait releases the lock then other thread can get-into the synchronized method and does it make sense because it may lead to race condition?
Here is my sample code that is allowing one and two thread into the synchronized block.
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
*
* #author Ashish Pancholi
*/
public class Test {
public Test() {
Sharing sharing = new Sharing();
Worker worker_ = new Worker(sharing);
Thread thread_ = new Thread(worker_, "one");
Worker worker = new Worker(sharing);
Thread thread = new Thread(worker, "two");
thread_.start();
thread.start();
}
public static void main(String[] argu) {
Test test = new Test();
}
public class Worker implements Runnable {
private Sharing sharing;
public Worker(Sharing sharing) {
this.sharing = sharing;
}
#Override
public void run() {
sharing.check();
}
}
public class Sharing {
public void check() {
synchronized (this) {
System.out.println("Thread IN " + Thread.currentThread().getName());
try {
wait(5000);
} catch (InterruptedException ex) {
}
System.out.println("Thread OUT " + Thread.currentThread().getName());
}
}
}
}
Output-
Thread IN one
Thread IN two
Thread OUT one
Thread OUT two
Yes it makes sense.
The API of the wait() method says:
Causes the current thread to wait until either another thread invokes
the notify() method or the notifyAll() method for this object, or a
specified amount of time has elapsed.
So if the wait method would NOT release the lock on the monitor object, no other thread could get it and thus no other thread could invoke notify or notifyAll on that monitor object.
The wait(5000) means that the current thread will wait up to 5000 milliseconds for a notification before continuing or continue after 5000 ms. If you want to hold the lock and pause 5000 ms then you must use Thread.sleep(5000).
It makes sense that there might be race conditions. Race conditions naturally happen when dealing with multiple threads. It is your job to prevent them by carefully managing your threads, and the wait method is an important tool that you can use to help with that.
Normally you wouldn't simply call wait with a fixed 5-second pause like that. In a real application you would probably be waiting for some specific condition to be true, so your wait looks more like this:
try {
while(!condition) {
wait();
}
doSomething();
} catch(InterruptedException e) {
doSomethingElseWhenWeAreAskedNotToWait();
}
Whether you have a race condition depends upon when condition becomes true, who else might be waiting for that condition, and what everyone does when it happens. The reason wait gives up the lock is to give condition a chance to become true while we wait.
You are using synchronized with two different locks, so there is no synchronization happening between the two threads.
Synchronize on the instance of Test rather than Sharing, and the behaviour will be quite different.

Waiting for an event in Java - how hard is it?

I have a thread that updates it's state from time to time and I want a second thread to be able to wait for the first thread to be done. Something like this:
Thread 1:
while(true) {
...do something...
foo.notifyAll()
...wait for some condition that might never happen...
...
}
Thread 2:
...
foo.wait();
...
Now this looks nice and all unless Thread 1's notifyAll() runs before Thread 2's wait(), in which case Thread 2 waits until Thread 1 notifies again (which might never happen).
My possible solutions:
a) I could use a CountDownLatch or a Future, but both have the problem that they inherently only run once. That is, in Thread 1's while loop, I would need to create a new foo to wait for each time and Thread 2 would need to ask which foo to wait for. I have a bad feeling about simply writing
while(true) {
foo = new FutureTask();
...
foo.set(...);
...wait for a condition that might never be set...
...
}
as I fear that at foo = new FutureTask(), what happens when someone waited for the old foo (for "some reason", set was not called, e.g. a bug in the exception handling)?
b) Or I could use a semaphore:
class Event {
Semaphore sem;
Event() { sem = new Semaphore(1); sem . }
void signal() { sem.release(); }
void reset() { sem.acquire(1); }
void wait() { if (sem.tryAcquire(1)) { sem.release(); } }
}
But I fear that there is some race condition, if multiple threads are wait()ing for it while another one signal()s and reset()s.
Question:
Is there nothing in the Java API that resembles the Windows Event behaviour? Or, if you despise Windows, something like golang's WaitGroup (i.e. a CountDownLatch that allows countUp())? Anything?
How to do it manually:
Thread 2 cannot simply wait because of spurious wakeup and in Java there is no way to know why Object.wait() returned. So I need a condition variable that stores whether the event is signalled or not. Thread 2:
synchronized(foo) {
while(!condition) {
foo.wait();
}
}
And Thread 1 of course sets condition to true in a synchronized block. Thanks to weekens for the hint!
Is there an existing class that wraps that behaviour?
Or do I need to copy and paste the code all over?
It is standard practice to change some state when performing notifyAll and to check some state when performing wait().
e.g.
boolean ready = false;
// thread 1
synchronized(lock) {
ready = true;
lock.notifyAll();
}
// thread 2
synchronized(lock) {
while(!ready)
lock.wait();
}
With this approach, it doesn't matter if thread 1 or thread 2 acquires the lock first.
Some coding analysis tools will give you a warning if you use notify or wait without setting a value or checking a value.
You could use a wait() with timeout, in which case you are not risking to wait forever. Also note that wait() may return even if there was no notify() at all, so, you'll need to wrap your wait inside some conditioned loop. That's the standard way of waiting in Java.
synchronized(syncObject) {
while(condition.isTrue()) {
syncObject.wait(WAIT_TIMEOUT);
}
}
(in your Thread 2)
Edit: Moved synchronized outside the loop.
The simplest way is just to say
firstThread.join();
This will be blocking until the first thread is terminated.
But you can implement the same using wait/notify. Unfortunately you have not posted your real code fragments but I guess that if wait does not exit when you call notify it happens because you did not put both into synchronized block. Pay attention that the "argument" of synchronized block must be the same for wait/notify pair.
I'd use a BlockingQueue between the two threads. Using wait and notify is so 5 minutes ago ;)
enum Event {
Event,
Stop;
}
BlockingQueue<Event> queue = new LinkedBlockingQueue<Event>();
// Thread 1
try {
while(true) {
...do something...
queue.put(Event.Event);
...wait for some condition that might never happen...
...
}
} finally {
// Tell other thread we've finished.
queue.put(Event.Stop};
}
// Thread 2
...
switch ( queue.take() ) {
case Event:
...
break;
default:
...
break;
}
Seems there is only ugly solutions. I solve it using AtomicBoolean as flag and some sleep to prevent high cpu usage and timeout for unexpected lost event...
Here my code:
somewhere in thread class:
private static final int WAIT_DELAY_MS_HACK = 5000; //ms
private static final AtomicBoolean NeedToExecute = new AtomicBoolean(false);
In working thread, that need to send wake signal:
public static final void SendSignalToExecute(){
synchronized(NeedToExecute){
NeedToExecute.set(true);
NeedToExecute.notify();
}
}
In the thread that must wait signal:
//To prevent infinite delay when notify was already lost I use WAIT_DELAY_MS_HACK in wait().
//To prevent false interruption on unknown reason of JM I use while and check of AtomicBoolean by NeedToExecute.get() in it.
//To prevent high CPU usage in for unknown persistant interruption in wait I use additional sleep():
while (!NeedToExecute.get()){
synchronized(NeedToExecute){
try {
NeedToExecute.wait(WAIT_DELAY_MS_HACK); //if notify() was sent before we go into wait() but after check in while() it will lost forever... note that NeedToExecute.wait() releases the synchronized lock for other thread and re-acquires it before returning
} catch (InterruptedException ex) { //here also may be sleep or break and return
}
}
sleep(100); //if wait() will not wait - must be outside synchronized block or it may cause freeze thread with SendSignalToExecute()... :(
}
NeedToExecute.set(false); //revert back to reenter check in next iteration, but I use it for one waited thread it cycle "do ... wait" if you use multiple thread you need to synchronise somehow this revert

is there a 'block until condition becomes true' function in java?

I'm writing a listener thread for a server, and at the moment I'm using:
while (true){
try {
if (condition){
//do something
condition=false;
}
sleep(1000);
} catch (InterruptedException ex){
Logger.getLogger(server.class.getName()).log(Level.SEVERE, null, ex);
}
}
With the code above, I'm running into issues with the run function eating all the cpu time looping. The sleep function works, but it seems be a makeshift fix, not a solution.
Is there some function which would block until the variable 'condition' became 'true'?
Or is continual looping the standard method of waiting until a variable's value changes?
Polling like this is definitely the least preferred solution.
I assume that you have another thread that will do something to make the condition true. There are several ways to synchronize threads. The easiest one in your case would be a notification via an Object:
Main thread:
synchronized(syncObject) {
try {
// Calling wait() will block this thread until another thread
// calls notify() on the object.
syncObject.wait();
} catch (InterruptedException e) {
// Happens if someone interrupts your thread.
}
}
Other thread:
// Do something
// If the condition is true, do the following:
synchronized(syncObject) {
syncObject.notify();
}
syncObject itself can be a simple Object.
There are many other ways of inter-thread communication, but which one to use depends on what precisely you're doing.
EboMike's answer and Toby's answer are both on the right track, but they both contain a fatal flaw. The flaw is called lost notification.
The problem is, if a thread calls foo.notify(), it will not do anything at all unless some other thread is already sleeping in a foo.wait() call. The object, foo, does not remember that it was notified.
There's a reason why you aren't allowed to call foo.wait() or foo.notify() unless the thread is synchronized on foo. It's because the only way to avoid lost notification is to protect the condition with a mutex. When it's done right, it looks like this:
Consumer thread:
try {
synchronized(foo) {
while(! conditionIsTrue()) {
foo.wait();
}
doSomethingThatRequiresConditionToBeTrue();
}
} catch (InterruptedException e) {
handleInterruption();
}
Producer thread:
synchronized(foo) {
doSomethingThatMakesConditionTrue();
foo.notify();
}
The code that changes the condition and the code that checks the condition is all synchronized on the same object, and the consumer thread explicitly tests the condition before it waits. There is no way for the consumer to miss the notification and end up stuck forever in a wait() call when the condition is already true.
Also note that the wait() is in a loop. That's because, in the general case, by the time the consumer re-acquires the foo lock and wakes up, some other thread might have made the condition false again. Even if that's not possible in your program, what is possible, in some operating systems, is for foo.wait() to return even when foo.notify() has not been called. That's called a spurious wakeup, and it is allowed to happen because it makes wait/notify easier to implement on certain operating systems.
As nobody published a solution with CountDownLatch. What about:
public class Lockeable {
private final CountDownLatch countDownLatch = new CountDownLatch(1);
public void doAfterEvent(){
countDownLatch.await();
doSomething();
}
public void reportDetonatingEvent(){
countDownLatch.countDown();
}
}
Similar to EboMike's answer you can use a mechanism similar to wait/notify/notifyAll but geared up for using a Lock.
For example,
public void doSomething() throws InterruptedException {
lock.lock();
try {
condition.await(); // releases lock and waits until doSomethingElse is called
} finally {
lock.unlock();
}
}
public void doSomethingElse() {
lock.lock();
try {
condition.signal();
} finally {
lock.unlock();
}
}
Where you'll wait for some condition which is notified by another thread (in this case calling doSomethingElse), at that point, the first thread will continue...
Using Locks over intrinsic synchronisation has lots of advantages but I just prefer having an explicit Condition object to represent the condition (you can have more than one which is a nice touch for things like producer-consumer).
Also, I can't help but notice how you deal with the interrupted exception in your example. You probably shouldn't consume the exception like this, instead reset the interrupt status flag using Thread.currentThread().interrupt.
This because if the exception is thrown, the interrupt status flag will have been reset (it's saying "I no longer remember being interrupted, I won't be able to tell anyone else that I have been if they ask") and another process may rely on this question. The example being that something else has implemented an interruption policy based on this... phew. A further example might be that your interruption policy, rather that while(true) might have been implemented as while(!Thread.currentThread().isInterrupted() (which will also make your code be more... socially considerate).
So, in summary, using Condition is rougly equivalent to using wait/notify/notifyAll when you want to use a Lock, logging is evil and swallowing InterruptedException is naughty ;)
You could use a semaphore.
While the condition is not met, another thread acquires the semaphore.
Your thread would try to acquire it with acquireUninterruptibly()
or tryAcquire(int permits, long timeout, TimeUnit unit) and would be blocked.
When the condition is met, the semaphore is also released and your thread would acquire it.
You could also try using a SynchronousQueue or a CountDownLatch.
Lock-free solution(?)
I had the same issue, but I wanted a solution that didn't use locks.
Problem: I have at most one thread consuming from a queue. Multiple producer threads are constantly inserting into the queue and need to notify the consumer if it's waiting. The queue is lock-free so using locks for notification causes unnecessary blocking in producer threads. Each producer thread needs to acquire the lock before it can notify the waiting consumer. I believe I came up with a lock-free solution using LockSupport and AtomicReferenceFieldUpdater. If a lock-free barrier exists within the JDK, I couldn't find it. Both CyclicBarrier and CoundDownLatch use locks internally from what I could find.
This is my slightly abbreviated code. Just to be clear, this code will only allow one thread to wait at a time. It could be modified to allow for multiple awaiters/consumers by using some type of atomic collection to store multiple owner (a ConcurrentMap may work).
I have used this code and it seems to work. I have not tested it extensively. I suggest you read the documentation for LockSupport before use.
/* I release this code into the public domain.
* http://unlicense.org/UNLICENSE
*/
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import java.util.concurrent.locks.LockSupport;
/**
* A simple barrier for awaiting a signal.
* Only one thread at a time may await the signal.
*/
public class SignalBarrier {
/**
* The Thread that is currently awaiting the signal.
* !!! Don't call this directly !!!
*/
#SuppressWarnings("unused")
private volatile Thread _owner;
/** Used to update the owner atomically */
private static final AtomicReferenceFieldUpdater<SignalBarrier, Thread> ownerAccess =
AtomicReferenceFieldUpdater.newUpdater(SignalBarrier.class, Thread.class, "_owner");
/** Create a new SignalBarrier without an owner. */
public SignalBarrier() {
_owner = null;
}
/**
* Signal the owner that the barrier is ready.
* This has no effect if the SignalBarrer is unowned.
*/
public void signal() {
// Remove the current owner of this barrier.
Thread t = ownerAccess.getAndSet(this, null);
// If the owner wasn't null, unpark it.
if (t != null) {
LockSupport.unpark(t);
}
}
/**
* Claim the SignalBarrier and block until signaled.
*
* #throws IllegalStateException If the SignalBarrier already has an owner.
* #throws InterruptedException If the thread is interrupted while waiting.
*/
public void await() throws InterruptedException {
// Get the thread that would like to await the signal.
Thread t = Thread.currentThread();
// If a thread is attempting to await, the current owner should be null.
if (!ownerAccess.compareAndSet(this, null, t)) {
throw new IllegalStateException("A second thread tried to acquire a signal barrier that is already owned.");
}
// The current thread has taken ownership of this barrier.
// Park the current thread until the signal. Record this
// signal barrier as the 'blocker'.
LockSupport.park(this);
// If a thread has called #signal() the owner should already be null.
// However the documentation for LockSupport.unpark makes it clear that
// threads can wake up for absolutely no reason. Do a compare and set
// to make sure we don't wipe out a new owner, keeping in mind that only
// thread should be awaiting at any given moment!
ownerAccess.compareAndSet(this, t, null);
// Check to see if we've been unparked because of a thread interrupt.
if (t.isInterrupted())
throw new InterruptedException();
}
/**
* Claim the SignalBarrier and block until signaled or the timeout expires.
*
* #throws IllegalStateException If the SignalBarrier already has an owner.
* #throws InterruptedException If the thread is interrupted while waiting.
*
* #param timeout The timeout duration in nanoseconds.
* #return The timeout minus the number of nanoseconds that passed while waiting.
*/
public long awaitNanos(long timeout) throws InterruptedException {
if (timeout <= 0)
return 0;
// Get the thread that would like to await the signal.
Thread t = Thread.currentThread();
// If a thread is attempting to await, the current owner should be null.
if (!ownerAccess.compareAndSet(this, null, t)) {
throw new IllegalStateException("A second thread tried to acquire a signal barrier is already owned.");
}
// The current thread owns this barrier.
// Park the current thread until the signal. Record this
// signal barrier as the 'blocker'.
// Time the park.
long start = System.nanoTime();
LockSupport.parkNanos(this, timeout);
ownerAccess.compareAndSet(this, t, null);
long stop = System.nanoTime();
// Check to see if we've been unparked because of a thread interrupt.
if (t.isInterrupted())
throw new InterruptedException();
// Return the number of nanoseconds left in the timeout after what we
// just waited.
return Math.max(timeout - stop + start, 0L);
}
}
To give a vague example of usage, I'll adopt james large's example:
SignalBarrier barrier = new SignalBarrier();
Consumer thread (singular, not plural!):
try {
while(!conditionIsTrue()) {
barrier.await();
}
doSomethingThatRequiresConditionToBeTrue();
} catch (InterruptedException e) {
handleInterruption();
}
Producer thread(s):
doSomethingThatMakesConditionTrue();
barrier.signal();
One could also leverage CompletableFutures (since Java 8):
final CompletableFuture<String> question = new CompletableFuture<>();
// from within the consumer thread:
final String answer = question.get(); // or: event.get(7500000, TimeUnit.YEARS)
// from within the producer thread:
question.complete("42");

Categories

Resources