I am writing producer and consumer code using wait() and notify() in Java.
Thread-0 is created and is invoked on produce() and Thread-1 is created and is invoked on consume().
public class Processor {
private volatile List<Integer> list = new ArrayList<>();
private final int MAX_CAPACITY = 5;
Object lock = new Object();
public void produce() throws InterruptedException {
while (true) {
while (list.size() == MAX_CAPACITY) {
System.out.println("List is full! Producer is Waiting....");
synchronized (lock) {
lock.wait();
}
}
synchronized (lock) {
int random = new Random().nextInt(100);
list.add(random);
System.out.println("Added to list:" + random);
lock.notify();
}
}
}
public void consume() throws InterruptedException {
while (true) {
while (list.size() == 0) {
System.out.println("List is empty!! Consumer is Waiting...");
synchronized (lock) {
lock.wait();
}
}
synchronized (lock) {
int i = list.remove(0);
System.out.println("Removed from list:" + i);
lock.notify();
}
}
}
}
The problem is that during execution, program stops after produce():
List is empty!! Consumer is Waiting...
Added to list:22
Added to list:45
Added to list:72
Added to list:91
Added to list:51
List is full! Producer is Waiting....
I am not able to understand what's the problem here. I somehow figured out that wrapping the code from while loop in synchronized block in produce() and consume() solves the problem.
produce()
synchronized (lock) {
while (list.size() == MAX_CAPACITY) {
System.out.println("List is full! Producer is Waiting....");
lock.wait();
}
consume
synchronized (lock) {
while (list.size() == 0) {
System.out.println("List is empty!! Consumer is Waiting...");
lock.wait();
}
}
What is the issue here? Is it a case of Thread starvation or deadlock?
Edit: Calling class:
public class App {
public static void main(String[] args) {
final Processor processor = new Processor();
Runnable r1 = new Runnable() {
#Override
public void run() {
try {
processor.produce();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Runnable r2 = new Runnable() {
#Override
public void run() {
try {
processor.consume();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
}
}
When you perform list.size() it is not thread safe and there is no guarentee you will ever see the value changed in another thread. The JIT could even inline the value if it detects you are not changing it in that thread.
By placing the synchronized block outside the loop you ensure a change in the value is visible (as it is also inside the while(true) loop.
Using synchronized outside loop creates read barrier. Therefore producer/consumer will see latest list inside loop where you are checking list.size(). That is why it works after you move while loop inside synchronized block.
In your case I would also suggest you to use single synchronized block in producer/consumer.
For example in your implementation if list.size() == 0 becomes false for consumer, it will release lock on lock object then in the next statement try to re-acquire lock again for consuming the data, which is unnecessary and inefficient. It should be like:
public void consume() throws InterruptedException {
while (true) {
synchronized (lock) {
while (list.size() == 0) {
System.out.println("List is empty!! Consumer is Waiting...");
lock.wait();
}
int i = list.remove(0);
System.out.println("Removed from list:" + i);
lock.notify();
}
}
}
Related
I want to use 3 threads to print A、B、C randomly,so I wrote code as below:
public class ThreadPrint4Test {
public static void main(String[] args) {
new ThreadPrint4Test().testPrint();
}
public void testPrint() {
Object lock = new Object();
new Thread(new PrintThread("A",lock),"thread-A").start();
new Thread(new PrintThread("B",lock),"thread-B").start();
new Thread(new PrintThread("C",lock),"thread-C").start();
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
new Thread(() -> {
synchronized (lock) {
lock.notifyAll();
}
}).start();
}
class PrintThread implements Runnable {
private Object lock;
private String value;
public PrintThread(String value, Object lock) {
this.value = value;
this.lock = lock;
}
public void run() {
while (true) {
try {
synchronized (lock) {
lock.wait();
System.out.println(LocalTime.now() + "\t" + value);
lock.notifyAll();
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
}
But when I test the program,it stoppted print characters after a few seconds
Using jps and jstack I found all the 3 threads are WAITING the object lock
I tested it for serveral times,and this phenomenon occurs every time.
I do not know why all the 3 threads are waiting object lock at same time
Based on my knowledge,each time one of the 3 threads will be awake and have the chance to exeute,then it will awake all the 3 threads randomly by invoking lock.notifyAll();. So the program should run continuous theoretically,But now each time I test it,it will stop print characters after a few seconds.
Could someone help analysis why this happen? Thanks in advance!
while (true) {
try {
synchronized (lock) {
lock.wait();
System.out.println(LocalTime.now() + "\t" + value);
lock.notifyAll();
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
Your problem is that you are calling notifyAll() immediately after calling wait(). You get to a deadlock situation where each thread is waiting. When all the threads are waiting, none of them can be notified, hence your program comes to a standstill.
According to the Concurrency tutorial, you need to wait() for a certain condition to occur. Once the condition occurs, you perform the required action (which, in your code, is printing the current time) then you call notifyAll() to inform the waiting threads that you have completed performing the required action and that they can try to perform their required action.
Explanations after the code.
import java.time.LocalTime;
public class ThreadPrint4Test {
private volatile boolean canPrint;
public void testPrint() {
Object lock = new Object();
new Thread(new PrintThread("A", lock), "thread-A").start();
new Thread(new PrintThread("B", lock), "thread-B").start();
new Thread(new PrintThread("C", lock), "thread-C").start();
}
class PrintThread implements Runnable {
private Object lock;
private String value;
public PrintThread(String value, Object lock) {
this.value = value;
this.lock = lock;
canPrint = true;
}
public void run() {
while (true) {
while (!canPrint) {
try {
synchronized (lock) {
System.out.printf("[%s] Waiting...%n", value);
lock.wait();
}
}
catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
synchronized (lock) {
canPrint = false;
System.out.println(LocalTime.now() + "\t" + value);
canPrint = true;
lock.notifyAll();
}
}
}
}
public static void main(String[] args) {
new ThreadPrint4Test().testPrint();
try {
Thread.sleep(2000);
}
catch (InterruptedException x) {
x.printStackTrace();
}
System.exit(0);
}
}
I added a canPrint flag. When it is true, then the thread can print the current time. When it is false, the thread must wait.
When the thread can print the current time, it first sets the flag to false so that no other thread can print.
After the thread has printed the current time, it sets the flag back to true and calls method notifyAll() which causes all waiting threads to stop waiting and re-check the canPrint flag.
The first thread to awake after canPrint has been set to true, sets the flag to false which causes all other threads to wait.
I got task from my professor related to Producer-Consumer problem.
The task is implement Producer-Consumer process, but
first process should increase its value by 5 each time
second process should divide its value by 2 each time.
I found some examples of code, but nothing about multiple processes. Here is one of them.
--
// Java program to implement solution of producer
// consumer problem.
import java.util.LinkedList;
public class Threadexample {
public static void main(String[] args)
throws InterruptedException
{
// Object of a class that has both produce()
// and consume() methods
final PC pc = new PC();
// Create producer thread
Thread t1 = new Thread(new Runnable() {
#Override
public void run()
{
try {
pc.produce();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
});
// Create consumer thread
Thread t2 = new Thread(new Runnable() {
#Override
public void run()
{
try {
pc.consume();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
});
// Start both threads
t1.start();
t2.start();
// t1 finishes before t2
t1.join();
t2.join();
}
// This class has a list, producer (adds items to list
// and consumber (removes items).
public static class PC {
// Create a list shared by producer and consumer
// Size of list is 2.
LinkedList<Integer> list = new LinkedList<>();
int capacity = 2;
// Function called by producer thread
public void produce() throws InterruptedException
{
int value = 0;
while (true) {
synchronized (this)
{
// producer thread waits while list
// is full
while (list.size() == capacity)
wait();
System.out.println("Producer produced-"
+ value);
// to insert the jobs in the list
list.add(value++);
// notifies the consumer thread that
// now it can start consuming
notify();
// makes the working of program easier
// to understand
Thread.sleep(1000);
}
}
}
// Function called by consumer thread
public void consume() throws InterruptedException
{
while (true) {
synchronized (this)
{
// consumer thread waits while list
// is empty
while (list.size() == 0)
wait();
// to retrive the ifrst job in the list
int val = list.removeFirst();
System.out.println("Consumer consumed-"
+ val);
// Wake up producer thread
notify();
// and sleep
Thread.sleep(1000);
}
}
}
}
}
Output:
Producer produced-0
Producer produced-1
Consumer consumed-0
Consumer consumed-1
Producer produced-2
I am not sure if I understand my task completely. Is it possible to implement given task on this code? I want you to give me some suggestions or any sources, so I can understand what to do.
Thank you all in advance!
If I correctly understand your problem from your description, you should change the field's value from two threads. You would like to create a class-level field and two synchronized methods for changing his value after that create two threads and call from them both operations alternately. I think you can write that:
public class Solution0 {
private volatile int count;
public synchronized void increment() throws InterruptedException {
count = count + 5;
Thread.sleep(1000);
notifyAll();
wait();
}
public synchronized void divide() throws InterruptedException {
count = count / 2;
Thread.sleep(1000);
notifyAll();
wait();
}
public static void main(String[] args) {
Solution0 solution = new Solution0();
Thread t1 = new Thread(() -> {
try {
while (true){
solution.increment();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread t2 = new Thread(() -> {
try {
while (true){
solution.divide();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t1.start();
t2.start();
}
}
Also, you can change the type of field count from int to double, if you need a real number.
In this case, will thread 1 actually be notified (while waiting for the reference instead of the object itself)?
static Object lock=new Object();
//Thread 1:
Object reference=lock;
reference.wait();
//Thread 2:
lock.notify();
The synchronized method evaluates the expression given to the synchronized block in order to figure out what lock to take. Then wait, notify, etc. need to be called on the same object, but whether the same variable is used is immaterial. The code evaluates the expression in order to get the object.
Now whether thread1 waits, is notified, and wakes up depends on the outcome of a race condition. If thread1 enters the wait method before thread2 calls notify, then thread2 will wait and then wake up once thread2 notifies. If thread2 calls notify before thread1 enters the wait method then thread1 waits forever.
Waiting for the reference or the object pointed to by that reference is the same thing since a lock is obtained on an object. No matter how many references are there, if they point to the same object in memory wait(), notify(), notifyall() will work seamlessly. Check out the code below.
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
public class ProducerConsumer {
private Queue<Integer> queue = new ArrayBlockingQueue<>(10);
private LinkedList<Integer> list = new LinkedList<>();
int limit = 10;
public static void main(String[] args) {
final ProducerConsumer pc = new ProducerConsumer();
final ProducerConsumer pcRef = pc;
Thread producer = new Thread(new Runnable() {
int i = 1;
#Override
public void run() {
while (true) {
synchronized (pcRef) {
while (pc.limit == pc.list.size()) {
try {
pcRef.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
pc.list.add(i);
System.out.println("Producer #work : " + pc.list.size());
pcRef.notify();
}
}
}
});
Thread consumer = new Thread(new Runnable() {
#Override
public void run() {
while (true) {
synchronized (pc) {
while (0 == pc.list.size()) {
try {
pc.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
int val = pc.list.removeFirst();
System.out.println("Consumer #work : " + pc.list.size() + " : " + val);
pc.notify();
}
}
}
});
producer.start();
consumer.start();
try {
producer.join();
consumer.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Comment the below line and you will see that the consumer thread is waiting to be notified.
pc.list.add(i);
System.out.println("Producer #work : " + pc.list.size());
//pcRef.notify();
I want the ProducerThread to produce random values upto 10 and then expect ConsumerThread to consumer those values of Queue. Somewhere Producer is generating adding the values more than once. I have a concept that when we call notify on an object than that Thread would release lock and give chance to Thread which was expecting updation.
Here is the code, please correct my understanding.
public class ProducerThread extends Thread {
Queue<Integer> values;
ProducerThread(Queue<Integer> values) {
this.values = values;
}
public void run() {
while(true) {
synchronized(values) {
double totalValues = Math.random()*10;
System.out.println("Going to populate total values:" + totalValues);
for (int i = 1; i <= totalValues; i++) {
values.add(i);
System.out.println("Value updated: " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
values.notify();
}
}
}
}
public class ConsumerThread extends Thread {
Queue<Integer> values;
ConsumerThread(Queue<Integer> values) {
this.values = values;
}
#Override
public void run() {
while(true) {
synchronized (values) {
try {
// Consumer Thread waits until values are populated by Producer Thread
if(values.isEmpty()) {
values.wait();
}
Iterator<Integer> iterateValues = values.iterator();
System.out.println("Going to consume values: " + values.size());
while (iterateValues.hasNext()) {
Integer removedValue = iterateValues.next();
System.out.println("Value deleted: " + removedValue);
}
values.clear();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
public class Test {
public static void main(String[] args) {
Queue<Integer> values = new LinkedList<Integer>();
ProducerThread producer = new ProducerThread(values);
ConsumerThread consumer = new ConsumerThread(values);
consumer.start();
producer.start();
}
}
Aha! You have encountered the dreaded race condition!
Immediately after notify returns in your ProducerThread, said thread still has the lock. The ConsumerThread, woken up by the notify, will see that the lock is not available, and will wait until it becomes available.
Then the ProducerThread gives up the lock, it will then enter a race with the ConsumerThread to take that lock back (ProducerThread by way of re-entering the synchronized block, and ConsumerThread by means of having to return from wait). There is no guarantee which of these will win.
If you want your ProducerThread to wait for the items to be consumed before producing more, you should consider another wait/notify for that scenario.
EDIT: This image might help to explain things a bit more clearly.
I have a following program:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class SimpleWaitNotify implements Runnable {
final static Object obj = new Object();
static boolean value = true;
public synchronized void flag() {
System.out.println("Before Wait");
try {
obj.wait();
} catch (InterruptedException e) {
System.out.println("Thread interrupted");
}
System.out.println("After Being Notified");
}
public synchronized void unflag() {
System.out.println("Before Notify All");
obj.notifyAll();
System.out.println("After Notify All Method Call");
}
public void run() {
if (value) {
flag();
} else {
unflag();
}
}
public static void main(String[] args) throws InterruptedException {
ExecutorService pool = Executors.newFixedThreadPool(4);
SimpleWaitNotify sWait = new SimpleWaitNotify();
pool.execute(sWait);
SimpleWaitNotify.value = false;
SimpleWaitNotify sNotify = new SimpleWaitNotify();
pool.execute(sNotify);
pool.shutdown();
}
}
When I wait on obj, I get the following exception Exception in thread "pool-1-thread-1" java.lang.IllegalMonitorStateException: current thread not owner for each of the two threads.
But if I use SimpleWaitNotify's monitor then the program execution is suspended. In other words, I think it suspends current execution thread and in turn the executor. Any help towards understanding what's going on would be duly appreciated.
This is an area1 where the theory and javadoc seem straightforward, and since there aren't many examples, conceptually left a big gap in me.
You're calling wait and notifyAll on obj, but you're synchronizing on this (because you've got synchronized methods).
In order to wait or notify, you need to "own" the monitor first. Unsynchronize the methods, and synchronize on obj instead:
public void flag() {
System.out.println("Before Wait");
synchronized (obj) {
try {
obj.wait();
} catch (InterruptedException e) {
System.out.println("Thread interrupted");
}
}
System.out.println("After Being Notified");
}
public void unflag() {
System.out.println("Before Notify All");
synchronized (obj) {
obj.notifyAll();
}
System.out.println("After Notify All Method Call");
}
Either synchronize on obj, or call wait and notify on this. The calling thread must hold the monitor of the same object on which these methods are called.
For example,
synchronized void flag() {
System.out.println("Before Wait");
try {
wait();
} catch (InterruptedException e) {
System.out.println("Thread interrupted");
}
System.out.println("After Being Notified");
}
In this example, the lock is held on this (when the modifier synchronized is used on a instance method, the monitor of the instance is acquired). So, the wait() method may be invoked on the implied instance this.
In order to coordinate the two threads, they need to share the same lock. The original version had a static obj that could be used as a lock, but it wasn't used in the synchronized blocks. Here is a better example:
class SimpleWaitNotify implements Runnable {
private final Object lock;
private final boolean wait;
SimpleWaitNotify(Object lock, boolean wait) {
this.lock = lock;
this.wait = wait;
}
public void flag() {
synchronized (lock) {
System.out.println("Before Wait");
try {
lock.wait();
System.out.println("After Being Notified");
} catch (InterruptedException ex) {
System.out.println("Thread interrupted");
}
}
}
public void unflag() {
synchronized(lock) {
System.out.println("Before Notify All");
lock.notifyAll();
System.out.println("After Notify All Method Call");
}
}
public void run() {
if (wait) {
flag();
} else {
unflag();
}
}
public static void main(String[] argv) throws Exception {
ExecutorService pool = Executors.newFixedThreadPool(4);
Object shared = new Object();
SimpleWaitNotify sWait = new SimpleWaitNotify(shared, true);
pool.execute(sWait);
SimpleWaitNotify sNotify = new SimpleWaitNotify(shared, false);
pool.execute(sNotify);
pool.shutdown();
}
}
Rather putting the direct statement pool.shutdown(), try as below.
while (!service.isTerminated())
{
service.shutdown();
}
So it will wait for till all the threads execution completes.