Semaphore-implemented Producer-Consumer oriented thread pool - java

I am currently working on an educational assignment in which i have to implement a Semaphore only thread-safe thread pool.
I mustn't use during my assignment: Synchronize wait notify sleep or any thread-safe API's.
firstly without getting too much into the code i have:
Implemented a Thread-safe queue (no two threads can queue\dequeue at the same time) (i have tested this problem with ConcurrentLinkedQueue and the problem persists)
The design itself:
Shared:
Tasks semaphore = 0
Available semaphore = 0
Tasks_Queue queue
Available_Queue queue
Worker Threads:
Blocked semaphore = 0
General Info:
Only manager(single thread) can dequeue Tasks_Queue and Available_Queue
Only App-Main(single thread) can enqueue tasks is Tasks_Queue
Each worker thread can enqueue themselves in Available_Queue
So we have a mix of a single producer, a single manager and several consumers.
When the app first starts each of the worker threads gets started and immediately enqueues itself in Available_Queue, releases Available semaphore and gets blocked acquiring it's personal Blocked semaphore.
Whenever App-Main queues a new task it releases Task Semaphore
Whenever Manager wishes to execute a new task it must first acquire both Tasks and Available semaphores.
My question:
during the app's runtime the function dequeue_worker() returns a null worker, even though a semaphore is placed to protect access to the queue when it is known that there are no available worker threads.
i have "solved" the problem by recursively calling dequeue_worker() if it draws a null thread, BUT doing so is suppose to make an acquisition of a semaphore permit lost forever. yet when i limit the amount of workers to 1 the worker does not get blocked forever.
1) what's the break-point of my original design?
2) why doesn't my "solution" break the design even further?!
Code snippets:
// only gets called by Worker threads: enqueue_worker(this);
private void enqueue_worker(Worker worker) {
available_queue.add(worker);
available.release();
}
// only gets called by App-Main (a single thread)
public void enqueue_task(Query query) {
tasks_queue.add(query);
tasks.release();
}
// only gets called by Manager(a single Thread)
private Worker dequeue_worker() {
Worker worker = null;
try {
available.acquire();
worker = available_queue.poll();
} catch (InterruptedException e) {
// shouldn't happen
} // **** the solution: ****
if (worker==null) worker = dequeue_worker(); // TODO: find out why
return worker;
}
// only gets called by Manager(a single Thread)
private Query dequeue_task() {
Query query = null;
try {
tasks.acquire();
query = tasks_queue.poll();
} catch (InterruptedException e) {
// shouldn't happen
}
return query;
}
// gets called by Manager (a single thread)
private void execute() { // check if task is available and executes it
Worker worker = dequeue_worker(); // available.down()
Query query = dequeue_task(); //task.down()
worker.setData(query);
worker.blocked.release();
}
And finally Worker's Run() method:
while (true) { // main infinite loop
enqueue_worker(this);
acquire(); // blocked.acquire();
<C.S>
available.release();
}

You are calling available.release() twice, once in enqueue_worker, second time in a main loop.

Related

multithread: java condition await timeout but can't return

Lock sharedLock = new ReentrantLock();
Condition condition = lock.newCondition();
main thread:
sharedLock.lock();
childThread.start();
condition.await(5, TimeUnit.SECONDS);
sharedLock.unlock();
child thread:
sharedLock.lock();
//do something, may take a long time
Thread.sleep(10);// sleep to simulate a long execution
condition.signal();
sharedLock.unlock();
Suppose child thread send a network request and wait for response, I want main thread wait at most 5 seconds, if timeout, retry the request. but when the await() timeout, it cannot acquire lock because child thread still hold it, so it still wait the lock until child thread release it, which takes 10 seconds.
How can I achieve my requirement that main thread wait child thread's signal, but have a bounded timeout?
This is not how your are supposed to do it, you are supposed to:
Create an ExecutorService (thread pool) for that you should check the methods of the class Executors to choose the best one in your case but Executors.newFixedThreadPool is a good start
Submit your task as a FutureTask to the thread pool
Then call get with a timeout
Manage properly the TimeoutException
Here is how it could be done:
// Total tries
int tries = 3;
// Current total of tries
int tryCount = 1;
do {
// My fake task to execute asynchronously
FutureTask<Void> task = new FutureTask<>(
() -> {
Thread.sleep(2000);
return null;
}
);
// Submit the task to the thread pool
executor.submit(task);
try {
// Wait for a result during at most 1 second
task.get(1, TimeUnit.SECONDS);
// I could get the result so I break the loop
break;
} catch (TimeoutException e) {
// The timeout has been reached
if (tryCount++ == tries) {
// Already tried the max allowed so we throw an exception
throw new RuntimeException(
String.format("Could execute the task after %d tries", tries),
e
);
}
}
} while (true);
How can I achieve my requirement that main thread wait child thread's
signal, but have a bounded timeout?
Here is how you can achieve your requirements:
Main Thread:
lock.lock();
try {
childThread.start();
condition.await(5, TimeUnit.SECONDS);
} finally {
sharedLock.lock();
}
The child thread:
try {
//do something, may take a long time
Thread.sleep(10);// sleep to simulate a long execution
} finally {
// Here we notify the main thread that the task is complete whatever
// the task failed or not
lock.lock();
try {
condition.signal();
} finally {
lock.unlock();
}
}
As you can see to work, the task must not be performed within the critical section, we only acquire the lock to notify the main thread nothing more. Otherwise if you execute the task within the critical section after the timeout the main thread will still need to acquire the lock once again and since the lock is actually owned by the child thread, it will need to wait anyway until the end of the task which makes the timeout totally useless.
NB: I renamed sharedLock to lock as a ReentrantLock is an exclusive lock not as shared lock, if you need a shared lock check the class Semaphore to define the total amount of permits.
Your code can be simplified with intrinsic lock.
Object sharedObj = new Object();
main thread:
synchronized (sharedObj) {
int retryCount = 0;
while (retryCount < maxRetry) {
sharedObj.wait(5000);
retryCount++;
}
}
child thread:
synchronized (sharedObj) {
//do something, may take a long time
Thread.sleep(10);// sleep to simulate a long execution
sharedObj.notify();
}
java condition await timeout but can't return
That's because the lock must be released so wait/await can return. So your child thread should be like:
//do something, may take a long time
Thread.sleep(10);// sleep to simulate a long execution
synchronized (sharedObj) {
sharedObj.notify();
}
Java's wait/notify is usually used to solve producer-consumer problem. And usually sharedObj shouldn't be holded for too long. Then your main thread can hold the lock again when the wait timeout.
Take a look at an in-production example: hadoop/hdfs/DFSOutputStream.java
The logic is simple, the producer creates packet and put it in dataQueue
// takes a long time to create packet
synchronized (dataQueue) {
dataQueue.addLast(packet);
dataQueue.notifyAll();
}
The consumer wait while dataQueue is empty:
synchronized (dataQueue) {
while ((!shouldStop() && dataQueue.size() == 0 &&... ) {
try {
dataQueue.wait(timeout);
} catch (InterruptedException e) {
LOG.warn("Caught exception", e);
}
doSleep = false;
now = Time.monotonicNow();
}
As you can see, the dataQueue are unlocked for most of the time!
How can I achieve my requirement that main thread wait child thread's signal, but have a bounded timeout?
If your child thread are mostly in a loop, your Main thread can set a isRunning flag to make child thread stop by itself. If your child thread are mostly blocking by an I/O operation, your Main thread can interrupt the child thread.
The sharedObj is used for coordination and protects sharedObj. If there's other resources should be protected, you have 2 choices:
1. If the operation on the resource is quick, like ackQueue in DFSOutputStream.java, protect it together inside the sharedObj.
2. If the operation on the resource is time-consuming, do it and protect it outside the sharedObj.
The valid confusion in the question is because the "Thread.sleep(10)" is done inside the lock block. When await(long time, TimeUnit unit) has to return because of timeout, it still needs the lock. So, as suggested in the other answer the long running task should not be inside the lock for it to work properly.
But it would be nice to have proper documentation stressing this fact. For example, if we await(5, TimeUnit.SECONDS) i.e wait for 5 seconds and the lock is available 10 seconds after the call, it will still return false even though the lock is available now at the moment of return.

Cancellation and Interruption in java

In Java Concurrency in Practice there is explanation about how to use cancellation and interruption in threads. This example is on Page 21 of Chapter 7 Cancellation and Shutdown, which states:
Listing 7.3. Unreliable Cancellation that can Leave Producers Stuck in a Blocking Operation. Don't Do this.
Here they are telling us in order to stop any thread operation just create a volatile flag which can be checked. Depending on the status of that flag thread execution stops.
Now there is one program for explaining same. It works fine there, below is the example:
public class PrimeGenerator implements Runnable {
#GuardedBy("this")
private final List<BigInteger> primes = new ArrayList<BigInteger>();
private volatile boolean cancelled;
public void run() {
BigInteger p = BigInteger.ONE;
while (!cancelled) {
p = p.nextProbablePrime();
synchronized (this) {
primes.add(p);
}
}
}
public void cancel() {
cancelled = true;
}
public synchronized List<BigInteger> get() {
return new ArrayList<BigInteger>(primes);
}
List<BigInteger> aSecondOfPrimes() throws InterruptedException {
PrimeGenerator generator = new PrimeGenerator();
new Thread(generator).start();
try {
SECONDS.sleep(1);
} finally {
generator.cancel();
}
return generator.get();
}
}
In the above code cancelled is the volatile flag which we can check for the cancellation check and thread execution stops if its true.
But if we do the same operation which we have done above but use BlockingQueue there is some problem.
If, however, a task that uses this approach calls a blocking method such as
BlockingQueue.put() we could have a more serious problem the task might never check the cancellation flag and therefore might never terminate.
BrokenPrimeProducer in below program illustrates this problem. The producer thread generates primes and places them on a blocking queue. If the producer gets ahead of the consumer, the queue will fill up and put() will block. What happens if the consumer tries to cancel the producer task while it is blocked in put()? It can call cancel which will set the cancelled flag but the producer will never check the flag because it will never emerge from the blocking put() (because the consumer has stopped retrieving primes from the queue).
Here is the code for the same:
class BrokenPrimeProducer extends Thread {
private final BlockingQueue<BigInteger> queue;
private volatile boolean cancelled = false;
BrokenPrimeProducer(BlockingQueue<BigInteger> queue) {
this.queue = queue;
}
public void run() {
try {
BigInteger p = BigInteger.ONE;
while (!cancelled) {
queue.put(p = p.nextProbablePrime());
}
} catch (InterruptedException consumed) {
}
}
public void cancel() {
cancelled = true;
}
void consumePrimes() throws InterruptedException {
BlockingQueue<BigInteger> primes =...;
BrokenPrimeProducer producer = new BrokenPrimeProducer(primes);
producer.start();
try {
while (needMorePrimes()) {
consume(primes.take());
}
} finally {
producer.cancel();
}
}
}
I am not able to understand why cancellation will not work in case of blocking Queue in second code example. Can someone explain?
This is explicitly because BlockingQueue#put(E) will block if it needs to while placing values inside of it. The code isn't in a position to check the flag again due to it being in a blocked state, so the fact that the flag is set to a different value at any other time is independent of the currently blocked thread.
The only real way to address the issue is to interrupt the thread, which will end the blocking operation.
When using a flag to cancel, there's no way to make the thread quit sleeping or waiting if it happens to have started sleeping or waiting, instead you have to wait for the sleep time to expire or for the wait to be ended with a notification. Blocking means a consumer thread sits in a wait state until something gets enqueued in an empty queue, or a producer thread sits in a wait state until there's room to put something in a full queue. The blocked thread never leaves the wait method -- it's as if you had a breakpoint on the line with the sleep or wait, and the thread is frozenon that line until the sleep time expires or until the thread gets a notification (not getting into spurious wakeups). The thread can't get to the line where it checks the flag.
Using interruption signals the thread to wake up if it is waiting or sleeping. You can't do that with a flag.
Cancellation flags need to be checked. Whereas interruption immediately notifies the thread blocked to throw InterruptedException, only the next iteration of the while loop will the thread know it's been changed - that is, when the thread unblocks and continues.
See the problem? The thread won't know if another thread set the flag. It's blocked. It can't go to the next iteration.
needMorePrimes() on some conditions return false, then the consumer will call producer.cancel(), at the same time, the producer fill the BlockingQueue full so that it block on queue.put(p = p.nextProbablePrime()) and can't check the cancelled status, so it's bad.

how to synchronize a set of multiple threads with respect to a single thread in Java

Suppose that I have an arraylist called myList of threads all of which are created with an instance of the class myRunnable implementing the Runnable interface, that is, all the threads share the same code to execute in the run() method of myRunnable. Now suppose that I have another single thread called singleThread that is created with an instance of the class otherRunnable implementing the Runnable interface.
The synchornization challenge I have to resolve for these threads is the following: I need all of the threads in myList to execute their code until certain point. Once reached this point, they shoud sleep. Once all and only all of the threads in myList are sleeping, then singleThread should be awakened (singleThread was already asleep). Then singleThread execute its own stuff, and when it is done, it should sleep and all the threads in myList should be awakened. Imagine that the codes are wrapped in while(true)'s, so this process must happen again and again.
Here is an example of the situation I've just described including an attempt of solving the synchronization problem:
class myRunnable extends Runnable
{
public static final Object lock = new Object();
static int count = 0;
#override
run()
{
while(true)
{
//do stuff
barrier();
//do stuff
}
}
void barrier()
{
try {
synchronized(lock) {
count++;
if (count == Program.myList.size()) {
count = 0;
synchronized(otherRunnable.lock) {
otherRunnable.lock.notify();
}
}
lock.wait();
}
} catch (InterruptedException ex) {}
}
}
class otherRunnable extend Runnable
{
public static final Object lock = new Object();
#override
run()
{
while(true)
{
try {
synchronized(lock) {
lock.wait();
} catch (InterruptedException ex) {}
// do stuff
try {
synchronized(myRunnable.lock) {
myRunnable.notifyAll();
}
}
}
}
class Program
{
public static ArrayList<Thread> myList;
public static void main (string[] args)
{
myList = new ArrayList<Thread>();
for(int i = 0; i < 10; i++)
{
myList.add(new Thread(new myRunnable()));
myList.get(i).start();
}
new Thread(new OtherRunnable()).start();
}
}
Basically my idea is to use a counter to make sure that threads in myList just wait except the last thread incrementing the counter, which resets the counter to 0, wakes up singleThread by notifying to its lock, and then this last thread goes to sleep as well by waiting to myRunnable.lock. In a more abstract level, my approach is to use some sort of barrier for threads in myList to stop their execution in a critical point, then the last thread hitting the barrier wakes up singleThread and goes to sleep as well, then singleThread makes its stuff and when finished, it wakes up all the threads in the barrier so they can continue again.
My problem is that there is a flaw in my logic (probably there are more). When the last thread hitting the barrier notifies otherRunnable.lock, there is a chance that an immediate context switch could occur, giving the cpu to singleThread, before the last thread could execute its wait on myRunnable.lock (and going to sleep). Then singleThread would execute all its stuff, would execute notifyAll on myRunnable.lock, and all the threads in myList would be awakened except the last thread hitting the barrier because it has not yet executed its wait command. Then, all those threads would do their stuff again and would hit the barrier again, but the count would never be equal to myList.size() because the last thread mentioned earlier would be eventually scheduled again and would execute wait. singleThread in turn would also execute wait in its first line, and as a result we have a deadlock, with everybody sleeping.
So my question is: what would be a good way to synchronize these threads in order to achieve the desired behaviour described before but at the same time in a way safe of deadlocks??
Based on your comment, sounds like a CyclicBarrier would fit your need exactly. From the docs (emphasis mine):
A synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point. CyclicBarriers are useful in programs involving a fixed sized party of threads that must occasionally wait for each other. The barrier is called cyclic because it can be re-used after the waiting threads are released.
Unfortunately, I haven't used them myself, so I can't give you specific pointers on them. I think the basic idea is you construct your barrier using the two-argument constructor with the barrierAction. Have your n threads await() on this barrier after this task is done, after which barrierAction is executed, after which the n threads will continue.
From the javadoc for CyclicBarrier#await():
If the current thread is the last thread to arrive, and a non-null barrier action was supplied in the constructor, then the current thread runs the action before allowing the other threads to continue. If an exception occurs during the barrier action then that exception will be propagated in the current thread and the barrier is placed in the broken state.

Rejection handler in Executors.newScheduledThreadPool

I have a ArrayBlocking queue, , upon which a single thread fixed rate Scheduled works.
I may have failed task. I want re-run that or re-insert in queue at high priority or top level
Some thoughts here -
Why are you using ArrayBlockingQueue and not PriorityBlockingQueue ? Sounds like what you need to me . At first set all your elements to be with equal priority.
In case you receive an exception - re-insert to the queue with a higher priority
Simplest thing might be a priority queue. Attach a retry number to the task. It starts as zero. After an unsuccessful run, throw away all the ones and increment the zeroes and put them back in the queue at a high priority. With this method, you can easily decide to run everything three times, or more, if you want to later. The down side is you have to modify the task class.
The other idea would be to set up another, non-blocking, thread-safe, high-priority queue. When looking for a new task, you check the non-blocking queue first and run what's there. Otherwise, go to the blocking queue. This might work for you as is, and so far it's the simplest solution. The problem is the high priority queue might fill up while the scheduler is blocked on the blocking queue.
To get around this, you'd have to do your own blocking. Both queues should be non-blocking. (Suggestion: java.util.concurrent.ConcurrentLinkedQueue.) After polling both queues with no results, wait() on a monitor. When anything puts something in a queue, it should call notifyAll() and the scheduler can start up again. Great care is needed lest the notification occur after the scheduler has checked both queues but before it calls wait().
Addition:
Prototype code for third solution with manual blocking. Some threading is suggested, but the reader will know his/her own situation best. Which bits of code are apt to block waiting for a lock, which are apt to tie up their thread (and core) for minutes while doing extensive work, and which cannot afford to sit around waiting for the other code to finish all needs to be considered. For instance, if a failed run can immediately be rerun on the same thread with no time-consuming cleanup, most of this code can be junked.
private final ConcurrentLinkedQueue mainQueue = new ConcurrentLinkedQueue();
private final ConcurrentLinkedQueue prioQueue = new ConcurrentLinkedQueue();
private final Object entryWatch = new Object();
/** Adds a new job to the queue. */
public void addjob( Runnable runjob ) {
synchronized (entryWatch) { entryWatch.notifyAll(); }
}
/** The endless loop that does the work. */
public void schedule() {
for (;;) {
Runnable run = getOne(); // Avoids lock if successful.
if (run == null) {
// Both queues are empty.
synchronized (entryWatch) {
// Need to check again. Someone might have added and notifiedAll
// since last check. From this point until, wait, we can be sure
// entryWatch is not notified.
run = getOne();
if (run == null) {
// Both queues are REALLY empty.
try { entryWatch.wait(); }
catch (InterruptedException ie) {}
}
}
}
runit( run );
}
}
/** Helper method for the endless loop. */
private Runnable getOne() {
Runnable run = (Runnable) prioQueue.poll();
if (run != null) return run;
return (Runnable) mainQueue.poll();
}
/** Runs a new job. */
public void runit( final Runnable runjob ) {
// Do everthing in another thread. (Optional)
new Thread() {
#Override public void run() {
// Run run. (Possibly in own thread?)
// (Perhaps best in thread from a thread pool.)
runjob.run();
// Handle failure (runit only, NOT in runitLast).
// Defining "failure" left as exercise for reader.
if (failure) {
// Put code here to handle failure.
// Put back in queue.
prioQueue.add( runjob );
synchronized (entryWatch) { entryWatch.notifyAll(); }
}
}
}.start();
}
/** Reruns a job. */
public void runitLast( final Runnable runjob ) {
// Same code as "runit", but don't put "runjob" in "prioQueue" on failure.
}

Does notify/notifyall release the lock being held

I am confused a bit about wait and notify/notifyAll.
I know there is a lock for every java object. I know wait will release the lock for other thread. How about notify/notifyall? Does notify/notifyAll release the lock it is holding for other thread?
No -- notify/notifyAll don't release locks like wait does. The awakened thread can't run until the code which called notify releases its lock.
This is what the Javadoc says:
The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up either through a call to the notify method or the notifyAll method. The thread then waits until it can re-obtain ownership of the monitor and resumes execution.
wait( ) tells the calling thread to give up the monitor and go to sleep until some other
thread enters the same monitor and calls notify( ).
notify( ) wakes up a thread that called wait( ) on the same object.
notifyAll( ) wakes up all the threads that called wait( ) on the same object. The
highest priority thread will run first.
I have to disagree with people who say notifyAll() releases the lock on the object over which waiting and notifying threads are being synchronized.
An example:
Consumer class contains a block:
synchronized(sharedObject){
if(sharedObject.isReadyToConsume() == false){
sharedObject.wait();
}else {
sharedObject.doTheThing();
System.out.println("consumer consuming...");
}
}
Scenario: Consumer class gets the lock on the sharedObject object, enters exclusively (it's inside the sync block) and sees that sharedObject has nothing ready yet (nothing to consume :) ) and it calls wait() method on the sharedObject. That way it releases the lock (stops the execution there!) and waits to be notified to continue when another Thread (Producer maybe) calls sharedObject.notify(); or sharedObject.notifyAll();. When it gets notified it continues from the wait() line
It's the sharedObject that keeps track of threads that asked it to be notified. When some Thread calls sharedObject.notifyAll() method the sharedObject will notify the waiting threads to wake up...
Now, the tricky part is that a thread naturally releases the lock of the object when it reaches the end of its synchronized(sharedObject){} block. THe question is what happens if I call notifyAll() in that block??? notifyAll() wakes up the waiting threads, but the lock is still owned by the Thread that has just call notifyAll()
Look at the Producer snippet:
synchronized(sharedObject){
//We are exlusively working with sharedObject and noone can enter it
[... changing the object ...]
sharedObject.notifyAll(); //notifying the waiting threads to wake up
Thread.sleep(1000); //Telling the current thread to go to sleep. It's holding the LOCK
System.out.println("awake...");
}
If notifyAll() would release the lock then the "awake..." would get printed out after the Consumer classes already start working with the sharedObject. This is not the case... The output shows that the Consumer is consuming the sharedObject after the Producer exits its sync block...
wait() - releases the lock and continues on the next line when it gets notified
notify(), notifyAll() - don't release the lock. They simply make waiting threads runnable again (not idle). They will have the right to enter when the
current thread reaches the end of its sync block and the Thread
scheduleder tells them that the lock has been released. The fight for
the lock begins again
Lets say bunch of Readers wants to read updated Value of certain Resource, which is going to be updated by Writer. Then how Reader knows that Resource Fields have been updated by Writer.
Therefore to Synchronize such cases between Readers and Writers on common resource, three final methods of Object class have been used.
wait()
notify()
notifyAll()
Wait : Readers wants to read updated value of resource, they register with resource object i.e when update happens on same object and when Writer notify it, readers will try to acquire lock on resource and read the updated resource.
- Wait only being invoked when Reader have Lock Object, here in our case it is resource.
- Once wait method is called, Reader releases the Lock Object.
- Now Only for the same registered Object(resource) Reader will get notification signals.
- If Reader invokes wait on Object, which is different from Object Writer used for sending notification, Reader will never gets the notification signal.
- Once Reader(s) are notified, now Reader(s) will try to content for the Lock(one of them gets the lock) read the updated value of resource. Similarly other Readers also gets turn to acquire lock and read the updated value.
- Once Reader read the updated value, perform there Business Logic and come out from Synchronized Block, Reader will release the lock so that other Readers can acquire it.
Notify: Writer enters the Synchronized Block, after acquiring lock performs his Business Logic, update the resource Object, once resource Object is updated it will notify the waiting threads(Readers) whom are waiting on same Lock.
- Notify signal to only one waiting Thread, which is decided by underlying Java Thread Manager
- Once Writer signals notify(), then it doesn't means Reader rushed immediately to read the updates values. Firstly writer must release the Lock, which it will do once it comes out of Synchronized block.Once Lock is being released and waiting threads are notified, then [In case of notify()] notified Thread will acquire the Lock[Released by Writer] and then enter the Synchronized Block and completes from where he left[i.e statements after wait()].
Notify-All: In notifyAll, all threads who are registered with resource lock, will get the notifications.
- Once notifyAll() is triggered, all threads waiting on same lock will get the signal and are ready in contention to acquire the lock.
- Once Writer finishes its Job and release the Lock, Any one Reader will acquire the lock[which Thread, again decided by underlying Java Thread Manager Implementation].
- Once the Reader gets the Lock, it will enter in Synchronized Block, where he left[i.e after wait() method] performs it tasks and on completing the Synchronized Block releases the Lock.
- Now Other remaining Threads will try to acquire the Lock, anyone of them will get it, enters synchronized block, completes its task and then release the Lock.
- This process will keep on till all Registered Readers complete there Job.
Now we will see the Code for it. Also we will discuss the Code also. :
Basic Overview Of code : It consists of Three classes
Resource Class : On which Lock will be acquired and wait() and notify(), notifyAll() will be invoked.
ReaderTask : Implements Runnable interface, implies readers jobs, wants to read updated Value of resource object.
WriterTask : Implements Runnable interface, implies writer jobs, will update the resource object and notify registered waiting threads.
Demo Class: which will create Let say 3 Readers and 1 Writer Thread, Bind Respective Tasks to them and start the threads.
Resource.java
public class Resource {
private String mesg;
public void setMesg(String mesg){
this.mesg =mesg;
}
public String getMesg(){
return this.mesg;
}
}
WaitThreadTask.java
public class WaitThreadTask implements Runnable {
private Resource resource;
public WaitThreadTask(Resource resource){
this.resource = resource;
}
#Override
public void run() {
// TODO Auto-generated method stub
synchronized(resource){
System.out.println("Before Reading Updated Value By : " +Thread.currentThread().getName() );
//We need to Take care to get the updated value, so waiting for writer thread to update value.
try {
//Release resource Lock & wait till any notification from Writer.
resource.wait();
System.out.println("Waiting is Over For : "+ Thread.currentThread().getName());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//Read Updated Value
System.out.println("Updated Value of Resource Mesg :" + resource.getMesg() + " Read By :" +Thread.currentThread().getName());
}
}
}
WriterThreadTask.java
public class WriterThreadTask implements Runnable{
private Resource resource;
public WriterThreadTask(Resource resource){
this.resource = resource;
}
#Override
public void run() {
// TODO Auto-generated method stub
synchronized(resource){
System.out.println("Before Updating Resource By : " + Thread.currentThread().getName());
//Updating resource Object Message
resource.setMesg("Hi How are You !!!");
resource.notify();
//resource.notifyAll();
//Once Writer Comes Out from Synch Block, Readers will Content to read the values.
System.out.println("Task Done By Writer Thread.");
}
}
}
ThreadDemo.java
public class ThreadDemo {
public static void main(String args[]){
//Create Single Resource Object, which can act as Lock on Writer and Readers.
Resource lock = new Resource();
//Three Readers and One Writer runnable Tasks.
Runnable taskR1 = new WaitThreadTask(lock);
Runnable taskR2 = new WaitThreadTask(lock);
Runnable taskR3 = new WaitThreadTask(lock);
Runnable taskW1 = new WriterThreadTask(lock);
Thread t1 = new Thread(taskR1, "Reader1");
Thread t2 = new Thread(taskR2, "Reader2");
Thread t3 = new Thread(taskR3, "Reader3");
Thread t4 = new Thread(taskW1, "Writer1");
t1.start();
t2.start();
t3.start();
/*try{
Thread.sleep(5000);
} catch(InterruptedException e){
e.printStackTrace();
}*/
t4.start();
}
}
Code Observations :
Both notify()/notifyAll() and wait() : works only on the Lock Objects they already acquire. For example : Synchornized(ObjectA) {......// ... // ObjectB.wait() or ObjectB.notify() or ObjectB.notifyAll() ...} then It will throw IllegalMonitorStateException. Therefore care must be taken that lock must be acquired before calling any of above three methods with same lock.Even If you simply write notify() or wait() or notifyAll(), then still it will throw IllegalMonitorStateException because [It suggest lock must be acquired on this Object, again which is not the case].
Reader will only able to receive signals on which same notification is send. If wait is happening on Object which is different from Object on which notification is being send, then Readers will never get the notification and hence they will wait forever.
Readers which are registered before Writer able to send the notification, Only those readers will get it. Because if Writer sends notification first, before reader registered to Object, they will not receive the signals as Signals are already being missed : Missed Signals
Reader and Writer should acquire Lock on same Object and should invoke wait/notification signals on same Object. If the above code is modified as, instead of using resource for locks and wait and notify, If we use this. What will happen ? Well .. All readers will wait forever, Because readers registered with different Objects of WaitThreadTask and writer notify on WriterThreadTask. Therefore none of the Reader will receive notification signals, as they registered to receive signals on respective WaitThreadTask Object and not on WriterThreadTask Object.
public class ProducerConsumerInJava {
public static void main(String args[]) {
System.out.println("How to use wait and notify method in Java");
System.out.println("Solving Producer Consumper Problem");
Queue<Integer> buffer = new LinkedList<>();
int maxSize = 10;
Thread producer = new Producer(buffer, maxSize, "PRODUCER");
Thread consumer = new Consumer(buffer, maxSize, "CONSUMER");
producer.start();
consumer.start();
}
}
class Producer extends Thread {
private Queue<Integer> queue;
private int maxSize;
public Producer(Queue<Integer> queue, int maxSize, String name){
super(name); this.queue = queue; this.maxSize = maxSize;
}
public void run() {
while (true) {
synchronized (queue) {
while (queue.size() == maxSize) {
try {
System.out .println("Queue is full, " +
"Producer thread waiting for " + "consumer to take
something from queue");
queue.wait();
} catch (Exception ex) {
ex.printStackTrace();
}
}
Random random = new Random();
int i = random.nextInt();
System.out.println("Producing value : " + i);
queue.add(i);
queue.notifyAll();
}
}
}
}
class Consumer extends Thread {
private Queue<Integer> queue;
private int maxSize;
public Consumer(Queue<Integer> queue, int maxSize, String name){
super(name); this.queue = queue; this.maxSize = maxSize;
}
public void run() {
while (true) {
synchronized (queue) {
while (queue.isEmpty()) {
try {
System.out .println("Queue is empty," +
"Consumer thread is waiting" +
" for producer thread to put something in queue");
queue.wait();
} catch (Exception ex) {
ex.printStackTrace();
}
}
System.out.println("Consuming value : " + queue.remove());
queue.notifyAll();
}
}
}
}
This is an example of Consumer and Producer program.
Output of the above program after execution is written below:
How to use wait and notify
method in Java Solving Producer Consumper Problem
Queue is empty,Consumer thread is waiting for producer thread to put
something in queue
Producing value : -1692411980
Producing value : 285310787
Producing value : -1045894970
Producing value : 2140997307
Producing value : 1379699468
Producing value : 912077154
Producing value : -1635438928
Producing value : -500696499
Producing value : -1985700664
Producing value : 961945684
Queue is full, Producer thread waiting for consumer to take something from
queue Consuming value : -1692411980
Consuming value : 285310787
Consuming value : -1045894970
Consuming value : 2140997307
Consuming value : 1379699468
Consuming value : 912077154
Consuming value : -1635438928
Consuming value : -500696499
Consuming value : -1985700664
Consuming value : 961945684
Queue is empty,Consumer thread is waiting for producer thread to put
something in queue
Producing value : 118213849
So, what we can conclude is, notifyAll() or notify() will not release the lock. have a look at the output, Producing value and Consuming value are not printed alternatively i.e there are printed separately.
Hence, notify/ notifyAll will not release lock
Read more: http://javarevisited.blogspot.com/2015/07/how-to-use-wait-notify-and-notifyall-in.html#ixzz57kdToLX6
To clarify my understanding and to provide an example for all to show when the lock is released, I have added print statements to the following code after the call to notify()/NotifyAll():
class ThreadDemo {
public static void main(String[] args) {
Shared s = new Shared();
new Producer(s).start();
new Consumer(s).start();
}
}
class Shared {
private char c = '\u0000';
private boolean writeable = true;
synchronized void setSharedChar(char c) {
while (!writeable)
try {
wait();
} catch (InterruptedException e) {
}
this.c = c;
writeable = false;
notifyAll();
System.out.println("setSharedChar notify() called - still in synchronized block.");
}
synchronized char getSharedChar() {
while (writeable)
try {
wait();
} catch (InterruptedException e) {
}
writeable = true;
notifyAll();
System.out.println("getSharedChar notify() called - still in synchronized block.");
return c;
}
}
class Producer extends Thread {
private Shared s;
Producer(Shared s) {
this.s = s;
}
public void run() {
System.out.println("Starting producer thread.");
for (char ch = 'A'; ch <= 'Z'; ch++) {
System.out.println("Producer thread getting ready to create a char.");
try {
Thread.sleep((int) (Math.random() * 1000));
} catch (InterruptedException e) {
}
s.setSharedChar(ch);
System.out.println(ch + " produced by producer.");
}
}
}
class Consumer extends Thread {
private Shared s;
Consumer(Shared s) {
this.s = s;
}
public void run() {
System.out.println("Starting consumer thread.");
char ch;
do {
System.out.println("Consumer thread getting ready to read a char.");
try {
Thread.sleep((int) (Math.random() * 1000));
} catch (InterruptedException e) {
}
ch = s.getSharedChar();
System.out.println(ch + " consumed by consumer.");
} while (ch != 'Z');
}
}
When I ran this example enough times, there was a point where I did eventually see the output of the program show:
...
F produced by producer.
Producer thread getting ready to create a char.
getSharedChar notify() called - still in synchronized block.
F consumed by consumer.
Consumer thread getting ready to read a char.
setSharedChar notify() called - still in synchronized block.
G produced by producer.
Producer thread getting ready to create a char.
getSharedChar notify() called - still in synchronized block.
setSharedChar notify() called - still in synchronized block.
G consumed by consumer.
Since the output getSharedChar is able to appear before setSharedChar, it appears that the lock is being released immediately or not required to reenter the synchronized getSharedChar() function by the call to notifyAll(). The lock may still be in place, but if you can reenter the function without it, what is the difference?
I was able to see similar output substituting notify() for notifyAll(). This was done on Java 1.7.0_15 on a 64 bit Windows 7 system.
wait(): Virtually every object in Java posses a monitor, to enter inside any synchronized block a thread has to first acquire this monitor and then only he can enter this synchronized block. As critical section of the code is executed by a single thread at a time so it has a great impact on overall performance of the application. So in place of holding the resource(monitor) threads can be asked to leave the critical section and wait for some time. To achieve this behaviour Java has provided a wait() api directly in Object class.
So any time a thread encounter a wait() API, it drops the current monitor plus all other monitors it holds and go to waiting state linked the current object. Its important to understand that that went to the waiting state in the context of object for which thread acquired the monitor first.. In a conceptual way i explain, every object holds a container house where all waiting threads are held.
There are multiple ways a Thread can come out of this container house of Object. Lets see..
When another thread comes and rings the bell once, In Java by calling
notify() method on the same object.
When another thread comes and rings multiple time, one of the Thread
gets a chance to come out of Object’s container house. In Java we can
do this by calling notifyAll() on the same object.
If we have the reference of the Thread waiting in container house.
Calling interrupt() on the Thread object pops it out of waiting state
and brings it the exception block of the Object.
There are overloaded wait(long milliseconds) and wait(long millSec,
int nanos) methods. As the time over the Thread is eligible to come
out of waiting state and contest for Object monitor again. In case
Thread fails to acquire the monitor after timeout also then it has to
wait for notify() calls only.
notify(): If the objects container house has multiple threads in waiting state then calling notify() on the this object given chance to one the thread to proceed. But after coming out of the waiting state the thread still has to contest for the object monitor and if it succeeds in getting the monitor it continue its execution otherwise thread will come back to waiting state. So notify() also has to be called from the synchronized block. If the notify() is not called from synchronized context then it thorws IllegalMonitorStateException.
notifyAll(): Calling notifyAll() on the Object makes sure all the threads in Object container house are awakened but once awakened they have to compete with each other or any other thread wants to acquire the object monitor. Which ever thread succeeds continue its executions others have to go back to waiting state and settle in object container house. As notify(), notifyAll() should also be called in synchronized context.
Explanation Taken from http://coder2design.com/thread-communication/
Calling notify() method on an object changes the state of the waiting threads.
The notifying thread only releases the lock once it completes the execution of its synchronized code on the lock object it is going to release.
So here's how it is:
wait()
If a thread calls wait() method on an object, the thread IMMEDIATELY releases the lock of that object and goes into waiting state.
notify()
But when a thread calls notify() method on an object, the thread does not release the lock of that object immediately, if the thread have some more job to do (i.e code to execute after notify() call). If the execution of the synchronized code is completed or there are no statements after notify(), then the thread releases the lock for waken up threads from waiting state.

Categories