I am trying to coordinate a producer and consumer thread problem. The producer puts 10 objects on the queue. That is the producer's run method just includes a simple loop to add 10 objects then it is finished. When the queue is full (queue is size 10) there is a call to wait() - > in the queue's add method. On the consumer side, the consumer starts by peeking at the objects and then it starts removing them. The problem I am having is that in roughly 50% of cases when the program is ran, the output terminates after the producer puts the 10 objects on queue. The other 50% of times the program works fine - that is the consumer takes off all the objects. My prior solution to this problem was to create a new consumer thread within the producer's run method. So once the producer had put ten objects on queue, the new consumer thread was created and I used join() to synchronize operations. However I would like to get the process working with wait and notify. Can someone please advise what I am doing wrong? thanks
#Override
public synchronized boolean add(Process element) {
if(isFull())
{
waitForNotify();
}
else
{
queue.add(element);
}
return true;
}
private void invokeNotify() {
try {
notify();
} catch (Exception e) {
e.printStackTrace();
}
}
private void waitForNotify() {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#Override
public synchronized boolean offer(Process element) throws IllegalStateException {
queue.add(element);
this.queue = newHeapSort.heapify(queue, queue.size());
return true;
}
#Override
public synchronized Process peek() {
if(queue.isEmpty())
{
waitForNotify();
}
return(queue.get(0));
}
#Override
public synchronized Process head() {
if(queue.isEmpty())
{
invokeNotify();
}
Process head = queue.get(0);
queue.remove(0);
return head;
}
The producer never notifies the consumer thread. So if the consumer is the first to start, it finds the queue empty, and waits eternally.
I would simply use a BlockingQueue, which does that for you.
If you really want to use wait() and notify(), you'll need to:
use a loop around your wait() calls, and go back to the waiting state if the condition to wake up is not true
decide when the producer should notify (normally, when it puts an item in the queue)
decide when the consumer should notify (normally, when it removes an item from the queue)
decide when the consumer should wait (normally, when the queue is empty)
decide when the producer should wait (normally, when the queue is full)
stop ignoring InterruptedException. Just let them propagate.
I would use notifyAll(), which would also make sure that everything works well if there are several producers or consumers.
Related
I have a producer and two consumers. I want to display how the consumers take the values from producer and displayed them.
The problem is that in my code only the second consumer displayed the item from producer.
How to solve this?
here is the problem:
public static void main(String[] args) throws Exception {
// Object of a class that has both produce()
// and consume() methods
final ProdConsumer pc = new ProdConsumer();
// Create producer thread
Thread t1 = new Thread(new Runnable() {
public void run() {
try {
pc.produce();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
// Create consumer thread
Thread t2 = new Thread(new Runnable() {
public void run() {
try {
pc.consume(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread t3 = new Thread(new Runnable() {
public void run() {
try {
pc.consume(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
// Start both threads
t1.start();
t2.start();
t3.start();
// // t1 finishes before t2
t1.join();
t2.join();
t3.join();
}
And producer_consumer class:
public class ProdCons
{
// Create a list shared by producer and consumer
// Size of list is 2.
LinkedList<Integer> list = new LinkedList<Integer>();
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(int thread) 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" + thread + " consumed-"
+ val);
// Wake up producer thread
notify();
// and sleep
Thread.sleep(1000);
}
}
}
}
Thank you
What am I missing?
wait/notify mechanism isn't fair, that means that if there are two threads waiting for the same resource, any of them could be notified when you call notify(). That sometimes is an issue of starvation problem.
So in your case when you are notifying first time, for example, first consumer gets this notification, and then after finishing his job it calls wait again, that means that on second time producer calls notify you have again two consumers waiting and then there is no guarantee that it would wake up another consumer, it could be any of them.
This problem will go away in case you will decrease Thread.sleep amount in producer, to be less than in consumer. Actually may be its not even a problem, because in your case throughput of consumer is the same as in producer, so basically you don't need second consumer, however its a rare case in real life, so to emulate the case when you have both consumers working, you should increase throughput of the producer.
However in my opinion you should really think before using such low level mechanism as wait/notify. Take a look at BlockingQueue, for example, or other concurrency primitives in java. For example you can make ArrayBlockingQueue to be fair:
Java doc: This class supports an optional fairness policy for ordering waiting producer and consumer threads. By default, this ordering is not guaranteed. However, a queue constructed with fairness set to true grants threads access in FIFO order. Fairness generally decreases throughput but reduces variability and avoids starvation.
So instead of list you will have this queue, and when calling take on this queue you will either get next element in a queue to consume or, in case its empty, your thread will block until there will be new elements.
And specifying fair flag to be true means that it will use FIFO for next consumer to wake up.
So your code will look like:
public class ProdCons {
// Create a queue shared by producer and consumer
// Size of list is 2.
BlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(2, true);
int capacity = 2;
// Function called by producer thread
public void produce() throws InterruptedException {
int value = 0;
while (true) {
System.out.println("Producer produced-" + value);
// to insert the jobs in the queue
// will block in case there is no more space in a queue
queue.put(value++);
// and sleep
Thread.sleep(500);
}
}
// Function called by consumer thread
public void consume(int thread) throws InterruptedException {
while (true) {
//retrieve the first job in the queue
//will block in case queue is empty, until its not empty
int val = queue.take();
System.out.println("Consumer" + thread + " consumed-"
+ val);
// and sleep
Thread.sleep(1000);
}
}
}
Also you may be interesting in this article explaining starvation and wait/notify fairness: http://tutorials.jenkov.com/java-concurrency/starvation-and-fairness.html
To illustrate my comment on the not using wait/notify, here's a producer/consumer with a BlockingQueue. Sorry if that doesn't actually answer your question about why the code doesn't work.
static final AtomicInteger value = new AtomicInteger();
public static void main(String[] args) {
BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(2);
Thread producer = new Thread(() -> { queue.put(value.getAndIncrement()) });
producer.start();
Runnable consumer1 = () -> {
try {
while(true) {
System.out.println("Consumer 1 consuming " + queue.take());
Thread.sleep(200);
}
}{ catch(Exception e) {}
};
Runnable consumer2 = () -> {
try {
while(true) {
System.out.println("Consumer 2 consuming " + queue.take());
Thread.sleep(200);
}
}{ catch(Exception e) {}
};
new Thread(consumer1).start();
new Thread(consumer2).start();
}
Side note, I usually wouldn't even create Thread objects directly but use an ExecutorService instead, but that's beside the point.
I would like to solve this problem in different way using java message queue(JMS) by publish and subscribe. The publish/subscribe messaging domain is a one-to-many model where one publisher sends the message through a topic to all the subscribers who are active and they receive the message through topic. it is simple and easy to implement. here is the details.
https://howtodoinjava.com/jms/jms-java-message-service-tutorial/
The t1.join t2.join t3.join will only let the main thread wait for the t1,t2,t3 producer and consumer threads to finish. In this case all threads run in while loop so join call doesn't make any difference. Also, a thread does not get to wait, if the synchronized block in that thread is not executed. Depending on who acquire the lock first, the synchronized blocks , will get executed.
First of all, you need to use .notifyAll(), not .notify() (which can be bad if one consumer notifies the other consumer; the producer would never wake).
Second, the data isn't sent to 2 lists but only one and the consumers are fighting to get from the same place; java has always said that there is no predictable thread scheduling under such case like sleep/wait/synchonized etc... Having only one consumer and the same repeatedly waking is within spec.
You need to use ReentrantLock(true) for a fair locking/waking.
Each of your threads is synchronized on itself (this), which will be different for each thread, so it won't prevent them from operating at the same time. Since they're (supposed to be) manipulating a list shared across the threads, they should probably synchronize on that list (or some other shared lock object). And, more problematically, it looks like each thread creates its own List - they won't share lists. The List should either be a static (class) list, or it should be passed in to each thread.
I have a scenario with dozens of producer and one single consumer. Timing is critical: for performance reason I want to avoid any locking of producers and I want the consumer to wait as little as possible when no messages are ready.
I've started using a ConcurrentLinkedQueue, but I don't like to call sleep on the consumer when queue.poll() == null because I could waste precious milliseconds, and I don't want to use yield because I end up wasting cpu.
So I came to implement a sort of ConcurrentBlockingQueue so that the consumer can run something like:
T item = queue.poll();
if(item == null) {
wait();
item = queue.poll();
}
return item;
And producer something like:
queue.offer(item);
notify();
Unfortunately wait/notify only works on synchronized block, which in turn would drastically reduce producer performance. Is there any other implementation of wait/notify mechanism that does not require synchronization?
I am aware of the risks related to not having wait and notify synchronized, and I managed to resolve them by having an external thread running the following:
while(true) {
notify();
sleep(100);
}
I've started using a ConcurrentLinkedQueue, but I don't like to call sleep on the consumer when queue.poll() == null
You should check the BlockingQueue interface, which has a take method that blocks until an item becomes available.
It has several implementations as detailed in the javadoc, but ConcurrentLinkedQueue is not one of them:
All Known Implementing Classes:
ArrayBlockingQueue, DelayQueue, LinkedBlockingDeque, LinkedBlockingQueue, LinkedTransferQueue, PriorityBlockingQueue, SynchronousQueue
I came out with the following implementation:
private final ConcurrentLinkedQueue<T> queue = new ConcurrentLinkedQueue<>();
private final Semaphore semaphore = new Semaphore(0);
private int size;
public void offer(T item) {
size += 1;
queue.offer(item);
semaphore.release();
}
public T poll(long timeout, TimeUnit unit) {
semaphore.drainPermits();
T item = queue.poll();
if (item == null) {
try {
semaphore.tryAcquire(timeout, unit);
} catch (InterruptedException ex) {
}
item = queue.poll();
}
if (item == null) {
size = 0;
} else {
size = Math.max(0, size - 1);
}
return item;
}
/** An inaccurate representation O(1)-access of queue size. */
public int size() {
return size;
}
With the following properties:
producers never go to SLEEP state (which I think can go with BlockingQueue implementations that use Lock in offer(), or with synchronized blocks using wait/notify)
consumer only goes to SLEEP state when queue is empty but it is soon woken up whenever a producer offer an item (no fixed-time sleep, no yield)
consumer can be sometime woken up even with empty queue, but it's ok here to waste some cpu cycle
Is there any equivalent implementation in jdk that I'm not aware of? Open for criticism.
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.
Can I get a complete simple scenario i.e. tutorial that suggest how this should be used, specifically with a Queue?
The wait() and notify() methods are designed to provide a mechanism to allow a thread to block until a specific condition is met. For this I assume you're wanting to write a blocking queue implementation, where you have some fixed size backing-store of elements.
The first thing you have to do is to identify the conditions that you want the methods to wait for. In this case, you will want the put() method to block until there is free space in the store, and you will want the take() method to block until there is some element to return.
public class BlockingQueue<T> {
private Queue<T> queue = new LinkedList<T>();
private int capacity;
public BlockingQueue(int capacity) {
this.capacity = capacity;
}
public synchronized void put(T element) throws InterruptedException {
while(queue.size() == capacity) {
wait();
}
queue.add(element);
notify(); // notifyAll() for multiple producer/consumer threads
}
public synchronized T take() throws InterruptedException {
while(queue.isEmpty()) {
wait();
}
T item = queue.remove();
notify(); // notifyAll() for multiple producer/consumer threads
return item;
}
}
There are a few things to note about the way in which you must use the wait and notify mechanisms.
Firstly, you need to ensure that any calls to wait() or notify() are within a synchronized region of code (with the wait() and notify() calls being synchronized on the same object). The reason for this (other than the standard thread safety concerns) is due to something known as a missed signal.
An example of this, is that a thread may call put() when the queue happens to be full, it then checks the condition, sees that the queue is full, however before it can block another thread is scheduled. This second thread then take()'s an element from the queue, and notifies the waiting threads that the queue is no longer full. Because the first thread has already checked the condition however, it will simply call wait() after being re-scheduled, even though it could make progress.
By synchronizing on a shared object, you can ensure that this problem does not occur, as the second thread's take() call will not be able to make progress until the first thread has actually blocked.
Secondly, you need to put the condition you are checking in a while loop, rather than an if statement, due to a problem known as spurious wake-ups. This is where a waiting thread can sometimes be re-activated without notify() being called. Putting this check in a while loop will ensure that if a spurious wake-up occurs, the condition will be re-checked, and the thread will call wait() again.
As some of the other answers have mentioned, Java 1.5 introduced a new concurrency library (in the java.util.concurrent package) which was designed to provide a higher level abstraction over the wait/notify mechanism. Using these new features, you could rewrite the original example like so:
public class BlockingQueue<T> {
private Queue<T> queue = new LinkedList<T>();
private int capacity;
private Lock lock = new ReentrantLock();
private Condition notFull = lock.newCondition();
private Condition notEmpty = lock.newCondition();
public BlockingQueue(int capacity) {
this.capacity = capacity;
}
public void put(T element) throws InterruptedException {
lock.lock();
try {
while(queue.size() == capacity) {
notFull.await();
}
queue.add(element);
notEmpty.signal();
} finally {
lock.unlock();
}
}
public T take() throws InterruptedException {
lock.lock();
try {
while(queue.isEmpty()) {
notEmpty.await();
}
T item = queue.remove();
notFull.signal();
return item;
} finally {
lock.unlock();
}
}
}
Of course if you actually need a blocking queue, then you should use an implementation of the BlockingQueue interface.
Also, for stuff like this I'd highly recommend Java Concurrency in Practice, as it covers everything you could want to know about concurrency related problems and solutions.
Not a queue example, but extremely simple :)
class MyHouse {
private boolean pizzaArrived = false;
public void eatPizza(){
synchronized(this){
while(!pizzaArrived){
wait();
}
}
System.out.println("yumyum..");
}
public void pizzaGuy(){
synchronized(this){
this.pizzaArrived = true;
notifyAll();
}
}
}
Some important points:
1) NEVER do
if(!pizzaArrived){
wait();
}
Always use while(condition), because
a) threads can sporadically awake
from waiting state without being
notified by anyone. (even when the
pizza guy didn't ring the chime,
somebody would decide try eating the
pizza.).
b) You should check for the
condition again after acquiring the
synchronized lock. Let's say pizza
don't last forever. You awake,
line-up for the pizza, but it's not
enough for everybody. If you don't
check, you might eat paper! :)
(probably better example would be
while(!pizzaExists){ wait(); }.
2) You must hold the lock (synchronized) before invoking wait/nofity. Threads also have to acquire lock before waking.
3) Try to avoid acquiring any lock within your synchronized block and strive to not invoke alien methods (methods you don't know for sure what they are doing). If you have to, make sure to take measures to avoid deadlocks.
4) Be careful with notify(). Stick with notifyAll() until you know what you are doing.
5)Last, but not least, read Java Concurrency in Practice!
Even though you asked for wait() and notify() specifically, I feel that this quote is still important enough:
Josh Bloch, Effective Java 2nd Edition, Item 69: Prefer concurrency utilities to wait and notify (emphasis his):
Given the difficulty of using wait and notify correctly, you should use the higher-level concurrency utilities instead [...] using wait and notify directly is like programming in "concurrency assembly language", as compared to the higher-level language provided by java.util.concurrent. There is seldom, if ever, reason to use wait and notify in new code.
Have you taken a look at this Java Tutorial?
Further, I'd advise you to stay the heck away from playing with this kind of stuff in real software. It's good to play with it so you know what it is, but concurrency has pitfalls all over the place. It's better to use higher level abstractions and synchronized collections or JMS queues if you are building software for other people.
That is at least what I do. I'm not a concurrency expert so I stay away from handling threads by hand wherever possible.
Example
public class myThread extends Thread{
#override
public void run(){
while(true){
threadCondWait();// Circle waiting...
//bla bla bla bla
}
}
public synchronized void threadCondWait(){
while(myCondition){
wait();//Comminucate with notify()
}
}
}
public class myAnotherThread extends Thread{
#override
public void run(){
//Bla Bla bla
notify();//Trigger wait() Next Step
}
}
The question asks for a wait() + notify() involving a queue(buffer). The first thing that comes to mind is a producer-consumer scenario using a buffer.
Three Components in our system:
Queue [Buffer] - A fixed-size queue shared between threads
Producer - A thread produces/inserts values to the buffer
Consumer - A thread consumes/removes values from the buffer
PRODUCER THREAD:
The producer inserts values in the buffer and until the buffer is full.
If the buffer is full, the producer call wait() and enters the wait stage, until the consumer awakes it.
static 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;
}
#Override
public void run() {
while (true) {
synchronized (queue) {
if (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.notify();
}
sleepRandom();
}
}
}
CONSUMER THREAD:
Consumer thread removes value from the buffer until the buffer is empty.
If the buffer is empty, consumer calls wait() method and enter wait state until a producer sends a notify signal.
static 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;
}
#Override
public void run() {
Random random = new Random();
while (true) {
synchronized (queue) {
if (queue.isEmpty()) {
System.out.println("Queue is empty," + "Consumer thread is waiting" + " for producer thread to put something in queue");
try {
queue.wait();
} catch (Exception ex) {
ex.printStackTrace();
}
}
System.out.println(" vvv Consuming value : " + queue.remove());
queue.notify();
}
sleepRandom();
}
}
}
UTIL METHOD:
public static void sleepRandom(){
Random random = new Random();
try {
Thread.sleep(random.nextInt(250));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Application Code:
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();
}
A Sample Output:
^^^ Producing value : 1268801606
vvv Consuming value : 1268801606
Queue is empty,Consumer thread is waiting for producer thread to put something in queue
^^^ Producing value : -191710046
vvv Consuming value : -191710046
^^^ Producing value : -1096119803
vvv Consuming value : -1096119803
^^^ Producing value : -1502054254
vvv Consuming value : -1502054254
Queue is empty,Consumer thread is waiting for producer thread to put something in queue
^^^ Producing value : 408960851
vvv Consuming value : 408960851
^^^ Producing value : 2140469519
vvv Consuming value : 65361724
^^^ Producing value : 1844915867
^^^ Producing value : 1551384069
^^^ Producing value : -2112162412
vvv Consuming value : -887946831
vvv Consuming value : 1427122528
^^^ Producing value : -181736500
^^^ Producing value : -1603239584
^^^ Producing value : 175404355
vvv Consuming value : 1356483172
^^^ Producing value : -1505603127
vvv Consuming value : 267333829
^^^ Producing value : 1986055041
Queue is full, Producer thread waiting for consumer to take something from queue
vvv Consuming value : -1289385327
^^^ Producing value : 58340504
vvv Consuming value : 1244183136
^^^ Producing value : 1582191907
Queue is full, Producer thread waiting for consumer to take something from queue
vvv Consuming value : 1401174346
^^^ Producing value : 1617821198
vvv Consuming value : -1827889861
vvv Consuming value : 2098088641
Example for wait() and notifyall() in Threading.
A synchronized static array list is used as resource and wait() method is called if the array list is empty. notify() method is invoked once a element is added for the array list.
public class PrinterResource extends Thread{
//resource
public static List<String> arrayList = new ArrayList<String>();
public void addElement(String a){
//System.out.println("Add element method "+this.getName());
synchronized (arrayList) {
arrayList.add(a);
arrayList.notifyAll();
}
}
public void removeElement(){
//System.out.println("Remove element method "+this.getName());
synchronized (arrayList) {
if(arrayList.size() == 0){
try {
arrayList.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}else{
arrayList.remove(0);
}
}
}
public void run(){
System.out.println("Thread name -- "+this.getName());
if(!this.getName().equalsIgnoreCase("p4")){
this.removeElement();
}
this.addElement("threads");
}
public static void main(String[] args) {
PrinterResource p1 = new PrinterResource();
p1.setName("p1");
p1.start();
PrinterResource p2 = new PrinterResource();
p2.setName("p2");
p2.start();
PrinterResource p3 = new PrinterResource();
p3.setName("p3");
p3.start();
PrinterResource p4 = new PrinterResource();
p4.setName("p4");
p4.start();
try{
p1.join();
p2.join();
p3.join();
p4.join();
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println("Final size of arraylist "+arrayList.size());
}
}
I have a situation where different threads populate a queue (producers) and one consumer retrieve element from this queue. My problem is that when one of these elements are retrieved from the queue some is missed (missing signal?). The producers code is:
class Producer implements Runnable {
private Consumer consumer;
Producer(Consumer consumer) { this.consumer = consumer; }
#Override
public void run() {
consumer.send("message");
}
}
and they are created and run with:
ExecutorService executor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 20; i++) {
executor.execute(new Producer(consumer));
}
Consumer code is:
class Consumer implements Runnable {
private Queue<String> queue = new ConcurrentLinkedQueue<String>();
void send(String message) {
synchronized (queue) {
queue.add(message);
System.out.println("SIZE: " + queue.size());
queue.notify();
}
}
#Override
public void run() {
int counter = 0;
synchronized (queue) {
while(true) {
try {
System.out.println("SLEEP");
queue.wait(10);
} catch (InterruptedException e) {
Thread.interrupted();
}
System.out.println(counter);
if (!queue.isEmpty()) {
queue.poll();
counter++;
}
}
}
}
}
When the code is run I get sometimes 20 elements added and 20 retrieved, but in other cases the elements retrieved are less than 20. Any idea how to fix that?
I'd suggest you use a BlockingQueue instead of a Queue. A LinkedBlockingDeque might be a good candidate for you.
Your code would look like this:
void send(String message) {
synchronized (queue) {
queue.put(message);
System.out.println("SIZE: " + queue.size());
}
}
and then you'd need to just
queue.take()
on your consumer thread
The idea is that .take() will block until an item is available in the queue and then return exactly one (which is where I think your implementation suffers: missing notification while polling). .put() is responsible for doing all the notifications for you. No wait/notifies needed.
The issue in your code is probably because you are using notify instead of notifyAll. The former will only wake up a single thread, if there is one waiting on the lock. This allows a race condition where no thread is waiting and the signal is lost. A notifyAll will force correctness at a minor performance cost by requiring all threads to wake up to check whether they can obtain the lock.
This is best explained in Effective Java 1st ed (see p.150). The 2nd edition removed this tip since programmers are expected to use java.util.concurrent which provides stronger correctness guarantees.
It looks like bad idea to use ConcurrentLinkedQueue and synchronization both at the same time. It defies the purpose of concurrent data structures in the first place.
There is no problem with ConcurrentLinkedQueue data structure and replacing it with BlockingQueue will solve the problem but this is not the root cause.
Problem is with queue.wait(10). This is timed wait method. It will acquire lock again once 10ms elapses.
Notification (queue.notify() ) will get lost because there is no consumer thread waiting on it if 10ms has elapsed.
Producer will not be able to add to the queue since they can't acquire lock because lock is claimed again by the consumer.
Moving to BlockingQueue solved your problem because you removed your wait(10) code and wait and notify was taken care by BlockingQueue data structure.