Thread will not execute run() when condition is met - java

I have a Java program that is simulating one way tunnel. A semaphore represents the tunnel, and there are two threads that represent the queues of traffic waiting on either side to pass through. In main, both threads are started as well as a thread to generate cars on either side every second. When a thread realizes its queue has cars in it, it attempts to acquire the semaphore. Once it has it, it allows each car to pass through, and releases the semaphore for the other side to use.
My problem is that it only is able to pass cars on the first try. After one side has claimed and released the semaphore, it seems that it will not be able to send cars through again. It seems to be that the if statement that is checking for cars in the queue is not executing.
class leftManager extends Thread {
private int leftQueue = 0;
private int total = 0;
static Semaphore semaphore;
public leftManager(Semaphore semaphore) {
this.semaphore = semaphore;
this.leftQueue = leftQueue;
}
public int getQueue() {
return leftQueue;
}
public void setQueue(int x) {
leftQueue += x;
}
#Override
public void run() {
try {
while (true) {
if (leftQueue > 0) {
System.out.println("Catch");
semaphore.acquire();
for (int i = 1; i <= leftQueue; i++) {
int temp = (leftQueue - (leftQueue - (i - 1)));
leftBoundPass pass = new leftBoundPass((temp * 2) + total);
pass.start();
try {
leftManager.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
total += leftQueue;
leftQueue = 0;
semaphore.release();
System.out.println("release");
}
else {
continue;
}
}
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
The rightManager is identical, other than different variable names and a different "boundPass" thread for the cars.
class leftBoundPass extends Thread {
private int car;
public leftBoundPass(int car) {
this.car = car;
}
#Override
public void run() {
System.out.println("Left-bound car " + car + " is in the tunnel.");
//This is one second of sleep
try {
leftBoundPass.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Left-bound car " + car + " is exiting the tunnel.");
}
}
The car generator is as follows:class trafficGenerator extends Thread {
leftManager left;
rightManager right;
public trafficGenerator(leftManager left, rightManager right) {
this.left = left;
this.right = right;
}
#Override
public void run() {
int random;
while (true) {
random = (int)(Math.random() * 2);
if (random == 0) {
System.out.println("Left-bound car wants to enter the tunnel");
left.setQueue(1);
//System.out.println(left.getQueue());
}
else {
System.out.println("Right-bound car wants to enter the tunnel");
right.setQueue(1);
}
try
{
Thread.sleep(2000);
}
catch(Exception e)
{
System.err.println(e);
}
}
}
}
Output:
Left-bound car wants to enter the tunnel
Catch
Left-bound car 0 is in the tunnel.
Left-bound car 0 is exiting the tunnel.
release
Left-bound car wants to enter the tunnel
Right-bound car wants to enter the tunnel
Right-bound car wants to enter the tunnel

Related

Java thread project weird behavior while increasing num of threads

I created a project for studying purposes that simulates a restaurant service using Threads. There is a Thread for Cook(s) to prepare a meal and another Thread for Waiter(s) to serve the meal. When I tested it with 1 cook and 5 waiters, it worked fine. But when I increase the number of cooks, the program runs indefinitely. What is wrong? Here is the code:
Class Main
package restaurant;
import java.util.concurrent.Semaphore;
public class Main {
public static int MAX_NUM_MEALS = 5;
public static int OLDEST_MEAL = 0;
public static int NEWEST_MEAL = -1;
public static int DONE_MEALS = 0;
public static int NUM_OF_COOKS = 1;
public static int NUM_OF_WAITERS = 5;
public static Semaphore mutex = new Semaphore(1);
static Cook cookThreads[] = new Cook[NUM_OF_COOKS];
static Waiter waiterThreads[] = new Waiter[NUM_OF_WAITERS];
public static void main(String[] args) {
for(int i = 0; i < NUM_OF_COOKS; i++) {
cookThreads[i] = new Cook(i);
cookThreads[i].start();
}
for(int i = 0; i < NUM_OF_WAITERS; i++) {
waiterThreads[i] = new Waiter(i);
waiterThreads[i].start();
}
try {
for(int i = 0; i < NUM_OF_COOKS; i++) {
cookThreads[i].join();
}
for(int i = 0; i < NUM_OF_WAITERS; i++) {
waiterThreads[i].join();
}
}catch(InterruptedException e) {
e.printStackTrace();
}
System.out.println("All done");
}
}
Class Cook
package restaurant;
public class Cook extends Thread{
private int id;
public Cook(int id) {
this.id = id;
}
public void run() {
while(true) {
System.out.println("Cook " + id + " is prepearing meal");
try {
Thread.sleep(1000);
Main.mutex.acquire();
Main.NEWEST_MEAL++;
Main.mutex.release();
Main.mutex.acquire();
Main.DONE_MEALS++;
Main.mutex.release();
System.out.println("Cook " + id + " has finished the meal");
if(Main.DONE_MEALS == 5) {
System.out.println("Cook " + id + " has finished his job");
break;
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Class Waiter
package restaurant;
public class Waiter extends Thread{
private int id;
public Waiter(int id) {
this.id = id;
}
public void run() {
while(true) {
System.out.println("Waiter " + id + " will check if there is any meal to serve");
if(Main.NEWEST_MEAL >= Main.OLDEST_MEAL) {
try {
Main.mutex.acquire();
Main.OLDEST_MEAL++;
Main.mutex.release();
System.out.println("Waiter " + id + " is picking up meal");
Thread.sleep(500);
System.out.println("Waiter " + id + " has delivered the meal to client");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(Main.DONE_MEALS == 5) {
System.out.println("Waiter " + id + " has finished his job");
break;
}
System.out.println("No meal to serve. Waiter " + id + " will come back later");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
Two issues:
Because you have two cooks, one of your cooks likely won't see Main.DONE_MEALS == 5. It will jump from 4 to 6 because of the other cook. Instead, check for Main.DONE_MEALS >= 5.
There is no guarantee that the cook or waiter threads will see the updates to Main.DONE_MEALS. Instead, consider having a private static final AtomicInteger field. The AtomicInteger class is a thread-safe integer implementation that enables other threads to see it in a thread-safe way.
The traditional fix would be:
a) You have to use the lock (mutex) not only when you write, but also when you read - otherwise it won't work correctly.
Just imagine you agreed on a signal to indicate if the bathroom is busy, but some just decide to ignore it - won't work!.
b) Check the condition before you do something.
Once you acquire the lock, you don't know the state so you should first check it before you proceed to make another meal. If you first check if there are already 5 done meals and only produce meals if there aren't yet 5, it should fix this problem, and you should only ever see done_meals <= 5 (you should review other parts of the code because it has similar problems, though).
Like others have mentioned, there are cleaner ways to write this but IMO your code is very suited for practice and understanding, so I'd try that rather than jumping for things like AtomicInteger.

Lock with 3 threads

I don't understand my mistake, i will describe it and then i will post my code.
From main() i want to run 3 threads (each thread containing a loop for 3 women).
I have a method that prints each woman that enters the bathroom and each woman that out.I want to use lock so every 3 women in each thread would be written before the next thread will take place.the out put should be something like this:
woman 0 enters the bathroom
woman 0 exits the bathroom
woman 1 enters the bathroom
woman 1 exits the bathroom
woman 2 enters the bathroom
woman 2 exits the bathroom
and then 2 times for each thread.
my problem is that only one thread is writing and 2 that didnt reach the lock still waiting after i release the lock.
here is my code:(BathRoom class)
private Lock lockW=new ReentrantLock();
public int women_present;
public BathRoom(){
women_present=0;//empty at start
}
public void woman_wants_to_enter (int i) {
lockW.lock();
women_present++;
System.out.println ("Woman " + i + " enters bathroom "); }
public void woman_leaves (int i) {
try {
Thread.sleep (1000);
}catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println ("Woman " + i + " exits bathroom ");
if((women_present%3)==0){
women_present=0;
lockW.unlock();
} }
This is the Women class:
private int i; /* This identifies the woman. */
private BathRoom bathroom;
public Woman (BathRoom bathroom,int i) {
this.i = i;
this.bathroom = bathroom;
}
public void run () {
for (int i = 0; i < 3; i++) {
try {
Thread.sleep ((long) (500 * Math.random()));
}catch (InterruptedException e) {
e.printStackTrace();
}
bathroom.woman_wants_to_enter (i);
bathroom.woman_leaves (i);
}
}}
i took the liberty to modify your code :
package stackoverflow;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class BathRoom {
private Lock lockW=new ReentrantLock();
private Condition c1=lockW.newCondition();
public int women_present;
public BathRoom(){
women_present=0;//empty at start
}
public void woman_wants_to_enter (int i) {
lockW.lock();
while(women_present!=i)
try {
c1.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println ("Woman " + i + " enters bathroom "); }
public void woman_leaves (int i) {
try {
Thread.sleep (1000);
}catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println ("Woman " + i + " exits bathroom ");
women_present++;
if(women_present==3){
women_present=0;
}
c1.signal();
lockW.unlock();
}
}
class Woman implements Runnable{
private int i; /* This identifies the woman. */
private BathRoom bathroom;
public Woman (BathRoom bathroom,int i) {
this.i = i;
this.bathroom = bathroom;
}
public void run () {
for (int i = 0; i < 3; i++) {
try {
Thread.sleep ((long) (500 * Math.random()));
}catch (InterruptedException e) {
e.printStackTrace();
}
bathroom.woman_wants_to_enter (i);
bathroom.woman_leaves (i);
}
}
}
public class testdummy {
public static void main(String[] args) {
BathRoom b=new BathRoom();
Woman w0=new Woman(b, 0);
Woman w1=new Woman(b, 1);
Woman w2=new Woman(b, 2);
Thread A=new Thread(w0);
Thread B=new Thread(w1);
Thread C=new Thread(w2);
A.start();
B.start();
C.start();
}
}
I have made use of Condition object to synchronize the thread access to the method , its not perfect but it works , hope it will give you thoughts for a better approach.
First thread
In woman_wants_to_enter(),
thread aquires lock() so continues.
woman_present is set to 1.
In woman_leaves(), woman_present is still 1
if (1 mod 3 is 1) so the unlock is not called
Second thread enters woman_wants_to_enter() but is waiting for the lock

Ski lift with capacity equals N.

I am learning about multithreading. It's my first task. I wrote this code and i can't move on. Task:
Ski lift with capacity equal N.
Clients have a weight (random Ki value) and They are threads that execute in
loop:
downhill(sleep(big random value)
Try to get into the lift (if the total weight of customers is
Less than or equal to N).
If it failed - they are waiting (sleep(small random value)
and re-execute the previous point.
if it was successful - they go up.
public class Client extends Thread
{
private SkiLift lift;
private int weight;
public Client(SkiLift l, int w)
{
this.lift = l;
this.weight=w;
}
public int getWeight()
{
return weight;
}
public void run()
{
for (int i =0; i<10; i++)
{
lift.downhill(this);
lift.goIn(this);
this.setPriority(MAX_PRIORITY);
lift.drive(this);
lift.goOut(this);
this.setPriority(5);
}
}
}
public class SkiLift
{
private static int actualLoad=0;
private static final int CAPACITY=300;
synchronized public void goIn(Client client)
{
try
{
System.out.println("Client " + client.getId() + " try to get into the lift");
while (actualLoad>CAPACITY)
{
System.out.println("The Lift is full!");
client.sleep((long) (Math.random()*1000));
wait();
}
}
catch (InterruptedException e) {}
System.out.println("Client " + client.getId() + "get into the lift " );
actualLoad+=client.getWeight();
System.out.println("actual load = " + actualLoad);
}
synchronized public void goOut (Client client)
{
System.out.println("Client "+ client.getId() + " leave the lift ");
actualLoad-=client.getWeight();
System.out.println("Actual load = " + actualLoad);
notifyAll();
}
public void downhill(Client client)
{
System.out.println("Client nr: " + client.getId()+ " downhill ");
try
{
client.sleep((long) (Math.random()*10000));
}
catch (InterruptedException e){}
}
public void drive(Client client)
{
try
{
client.sleep(9000);
}
catch (InterruptedException e){e.printStackTrace();}
}
}
I have three problems and i can't solve them:
The first who will enter must to be the first who has attempted to enter. (Just like in a queue)
The client who first came on the lift must also be the first to go down.
What is the moniotor in my program?
Thanks in advance :)
I think this question belongs to Codereview
Your Client should have a state like "topOfTheMountainReached", "liftStationReached", "liftEntered", ...
Your Client then waits for this events to happen. That's also the answer to your question which element to monitor - the state, or the client itself.
For the queue you can use a ArrayListBlockingQueue.
Your SkiLift then has to wait for new Clients to arrive and put them into the lift. As soon the client enters the lift, the client also gets notified that it has entered the lift. The Lift also notifies the client when the top is reached.
Here is an example of how such solution could look like.
It uses the Java Executor Service to schedule the events for getting the client out of the lift and for reaching the lift station at the end oft the downhill part. This may also be solved differently.
The Client:
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Client implements Runnable{
final ScheduledExecutorService dhexceutors = Executors.newScheduledThreadPool(500);
final static Random DHRANDOM = new Random();
final long weight;
public enum State {
goDownhill,
waitForLift,
goUp,
onTop,
}
private State state;
public SkiLift lift;
public Client(long weight,SkiLift lift) {
this.lift = lift;
this.weight = weight;
this.state = State.onTop;
goDownHill();
}
private void enterLift() {
lift.add(this);
}
private void goDownHill() {
synchronized (this) {
state = State.goDownhill;
this.notify();
}
dhexceutors.schedule(() -> {
liftStationReached();
}, DHRANDOM.nextInt(500), TimeUnit.MILLISECONDS);
}
public void liftStationReached() {
synchronized(this) {
state = State.waitForLift;
this.notify();
}
}
public void topReached() {
synchronized(this) {
state = State.onTop;
this.notify();
}
}
public void liftEntered() {
synchronized(this) {
state = State.goUp;
this.notify();
}
}
public void run() {
synchronized(this) {
while (true) {
try {
this.wait();
switch (state) {
case waitForLift:
enterLift();
break;
case goUp:
// just wait for the topReached event
break;
case goDownhill:
// just wait for reaching the lift.
break;
case onTop:
goDownHill();
break;
}
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
}
}
}
}
The Lift:
package skilift;
import java.util.ArrayList;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class SkiLift implements Runnable{
private ScheduledExecutorService getOutClientExecutor;
public SkiLift() {
getOutClientExecutor = Executors.newScheduledThreadPool(50);
waitingClientsQueue = new ArrayBlockingQueue<>(1000);
occupiedSeats = new ArrayList<>();
}
private final ArrayList<Client> occupiedSeats;
private long usedCapacity;
private final ArrayBlockingQueue<Client> waitingClientsQueue;
private final long capacity = 500;
public void add(Client client) {
synchronized(waitingClientsQueue) {
waitingClientsQueue.add(client);
waitingClientsQueue.notify();
}
}
private synchronized void occupySeat(Client client) {
occupiedSeats.add(client);
usedCapacity += client.weight;
}
private synchronized void getClientOut(Client client) {
occupiedSeats.remove(client);
usedCapacity -= client.weight;
// notify the waitingClientQueue that the capacity has changed
synchronized (waitingClientsQueue) {
waitingClientsQueue.notify();
}
client.topReached();
}
public void run() {
while (true) {
synchronized(waitingClientsQueue) {
try {
if (!waitingClientsQueue.isEmpty()) {
Client c = waitingClientsQueue.peek();
if (usedCapacity + c.weight <= capacity) {
occupySeat(waitingClientsQueue.poll());
getOutClientExecutor.schedule(() -> {
getClientOut(c);
}, 2, TimeUnit.SECONDS);
} else {
waitingClientsQueue.wait();
}
} else {
waitingClientsQueue.wait();
}
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
}
}
}
}
Apparently, the bottleneck in your system is the lift. You can only have N concurrent users of the lift.
Also, 3. mentions a Monitor. After some reading what a monitor is, you should figure out that it allows exclusive access to the limited resource, the lift.
So design your lift access to try to acquire one of the N monitors, wait a while, and at the end do not forget to release the monitor, so someone else can get it.

producer - consumer multithreading in Java

I want to write program using multithreading wait and notify methods in Java.
This program has a stack (max-length = 5). Producer generate number forever and put it in the stack, and consumer pick it from stack.
When stack is full producer must wait and when stack is empty consumers must wait.
The problem is that it runs just once, I mean once it produce 5 number it stops but i put run methods in while(true) block to run nonstop able but it doesn't.
Here is what i tried so far.
Producer class:
package trail;
import java.util.Random;
import java.util.Stack;
public class Thread1 implements Runnable {
int result;
Random rand = new Random();
Stack<Integer> A = new Stack<>();
public Thread1(Stack<Integer> A) {
this.A = A;
}
public synchronized void produce()
{
while (A.size() >= 5) {
System.out.println("List is Full");
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
result = rand.nextInt(10);
System.out.println(result + " produced ");
A.push(result);
System.out.println(A);
this.notify();
}
#Override
public void run() {
System.out.println("Producer get started");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
while (true) {
produce();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
And the consumer:
package trail;
import java.util.Stack;
public class Thread2 implements Runnable {
Stack<Integer> A = new Stack<>();
public Thread2(Stack<Integer> A) {
this.A = A;
}
public synchronized void consume() {
while (A.isEmpty()) {
System.err.println("List is empty" + A + A.size());
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.err.println(A.pop() + " Consumed " + A);
this.notify();
}
#Override
public void run() {
System.out.println("New consumer get started");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
while (true) {
consume();
}
}
}
and here is the main method:
public static void main(String[] args) {
Stack<Integer> stack = new Stack<>();
Thread1 thread1 = new Thread1(stack);// p
Thread2 thread2 = new Thread2(stack);// c
Thread A = new Thread(thread1);
Thread B = new Thread(thread2);
Thread C = new Thread(thread2);
A.start();
B.start();
C.start();
}
I think it will be better for understanding and dealing with synchronisation in general if you try to separate three things which are currently mixed:
Task which is going to do the actual job. Names for classes Thread1 & Thread2 are misleading. They are not Thread objects, but they are actually jobs or tasks implementing Runnable interface you are giving to Thread objects.
Thread object itself which you are creating in main
Shared object which encapsulates synchronised operations/logic on a queue, a stack etc. This object will be shared between tasks. And inside this shared object you will take care of add/remove operations (either with synchronized blocks or synchronized methods). Currently (as it was pointed out already), synchronization is done on a task itself (i.e. each task waits and notifies on its own lock and nothing happens). When you separate concerns, i.e. let one class do one thing properly it will eventually become clear where is the problem.
Your consumer and you producer are synchronized on different objects and do not block each other. If this works, I daresay it's accidental.
Read up on java.util.concurrent.BlockingQueue and java.util.concurrent.ArrayBlockingQueue. These provide you with more modern and easier way to implement this pattern.
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html
You should synchronize on the stack instead of putting it at the method level try this code.
Also don't initalize the stack in your thread classes anyways you are passing them in the constructor from the main class, so no need of that.
Always try to avoid mark any method with synchronized keyword instead of that try to put critical section of code in the synchronized block because the more size of your synchronized area more it will impact on performance.
So, always put only that code into synchronized block that need thread safety.
Producer Code :
public void produce() {
synchronized (A) {
while (A.size() >= 5) {
System.out.println("List is Full");
try {
A.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
result = rand.nextInt(10);
System.out.println(result + " produced ");
A.push(result);
System.out.println("stack ---"+A);
A.notifyAll();
}
}
Consumer Code :
public void consume() {
synchronized (A) {
while (A.isEmpty()) {
System.err.println("List is empty" + A + A.size());
try {
System.err.println("wait");
A.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.err.println(A.pop() + " Consumed " + A);
A.notifyAll();
}
}
Try this:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class CircularArrayQueue<T> {
private volatile Lock rwLock = new ReentrantLock();
private volatile Condition emptyCond = rwLock.newCondition();
private volatile Condition fullCond = rwLock.newCondition();
private final int size;
private final Object[] buffer;
private volatile int front;
private volatile int rare;
/**
* #param size
*/
public CircularArrayQueue(int size) {
this.size = size;
this.buffer = new Object[size];
this.front = -1;
this.rare = -1;
}
public boolean isEmpty(){
return front == -1;
}
public boolean isFull(){
return (front == 0 && rare == size-1) || (front == rare + 1);
}
public void enqueue(T item){
try {
// get a write lock
rwLock.lock();
// if the Q is full, wait the write lock
if(isFull())
fullCond.await();
if(rare == -1){
rare = 0;
front = 0;
} else if(rare == size - 1){
rare = 0;
} else {
rare ++;
}
buffer[rare] = item;
//System.out.println("Added\t: " + item);
// notify the reader
emptyCond.signal();
} catch(InterruptedException e){
e.printStackTrace();
} finally {
// unlock the write lock
rwLock.unlock();
}
}
public T dequeue(){
T item = null;
try{
// get the read lock
rwLock.lock();
// if the Q is empty, wait the read lock
if(isEmpty())
emptyCond.await();
item = (T)buffer[front];
//System.out.println("Deleted\t: " + item);
if(front == rare){
front = rare = -1;
} else if(front == size - 1){
front = 0;
} else {
front ++;
}
// notify the writer
fullCond.signal();
} catch (InterruptedException e){
e.printStackTrace();
} finally{
// unlock read lock
rwLock.unlock();
}
return item;
}
}
You can use Java's awesome java.util.concurrent package and its classes.
You can easily implement the producer consumer problem using the
BlockingQueue. A BlockingQueue already supports operations that wait
for the queue to become non-empty when retrieving an element, and wait
for space to become available in the queue when storing an element.
Without BlockingQueue, every time we put data to queue at the producer
side, we need to check if queue is full, and if full, wait for some
time, check again and continue. Similarly on the consumer side, we
would have to check if queue is empty, and if empty, wait for some
time, check again and continue. However with BlockingQueue we don’t
have to write any extra logic than to just add data from Producer and
poll data from Consumer.
Read more From:
http://javawithswaranga.blogspot.in/2012/05/solving-producer-consumer-problem-in.html
http://www.javajee.com/producer-consumer-problem-in-java-using-blockingqueue
use BlockingQueue,LinkedBlockingQueue this was really simple.
http://developer.android.com/reference/java/util/concurrent/BlockingQueue.html
package javaapplication;
import java.util.Stack;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ProducerConsumer {
public static Object lock = new Object();
public static Stack stack = new Stack();
public static void main(String[] args) {
Thread producer = new Thread(new Runnable() {
int i = 0;
#Override
public void run() {
do {
synchronized (lock) {
while (stack.size() >= 5) {
try {
lock.wait();
} catch (InterruptedException e) {
}
}
stack.push(++i);
if (stack.size() >= 5) {
System.out.println("Released lock by producer");
lock.notify();
}
}
} while (true);
}
});
Thread consumer = new Thread(new Runnable() {
#Override
public void run() {
do {
synchronized (lock) {
while (stack.empty()) {
try {
lock.wait();
} catch (InterruptedException ex) {
Logger.getLogger(ProdCons1.class.getName()).log(Level.SEVERE, null, ex);
}
}
while(!stack.isEmpty()){
System.out.println("stack : " + stack.pop());
}
lock.notifyAll();
}
} while (true);
}
});
producer.start();
consumer.start();
}
}
Have a look at this code example:
import java.util.concurrent.*;
import java.util.Random;
public class ProducerConsumerMulti {
public static void main(String args[]){
BlockingQueue<Integer> sharedQueue = new LinkedBlockingQueue<Integer>();
Thread prodThread = new Thread(new Producer(sharedQueue,1));
Thread consThread1 = new Thread(new Consumer(sharedQueue,1));
Thread consThread2 = new Thread(new Consumer(sharedQueue,2));
prodThread.start();
consThread1.start();
consThread2.start();
}
}
class Producer implements Runnable {
private final BlockingQueue<Integer> sharedQueue;
private int threadNo;
private Random rng;
public Producer(BlockingQueue<Integer> sharedQueue,int threadNo) {
this.threadNo = threadNo;
this.sharedQueue = sharedQueue;
this.rng = new Random();
}
#Override
public void run() {
while(true){
try {
int number = rng.nextInt(100);
System.out.println("Produced:" + number + ":by thread:"+ threadNo);
sharedQueue.put(number);
Thread.sleep(100);
} catch (Exception err) {
err.printStackTrace();
}
}
}
}
class Consumer implements Runnable{
private final BlockingQueue<Integer> sharedQueue;
private int threadNo;
public Consumer (BlockingQueue<Integer> sharedQueue,int threadNo) {
this.sharedQueue = sharedQueue;
this.threadNo = threadNo;
}
#Override
public void run() {
while(true){
try {
int num = sharedQueue.take();
System.out.println("Consumed: "+ num + ":by thread:"+threadNo);
Thread.sleep(100);
} catch (Exception err) {
err.printStackTrace();
}
}
}
}
Notes:
Started one Producer and two Consumers as per your problem statement
Producer will produce random numbers between 0 to 100 in infinite loop
Consumer will consume these numbers in infinite loop
Both Producer and Consumer share lock free and Thread safe LinkedBlockingQueue which is Thread safe. You can remove wait() and notify() methods if you use these advanced concurrent constructs.
Seems like you skipped something about wait(), notify() and synchronized.
See this example, it should help you.

IllegalMonitorStateException when notifying threads

I have a program that simulates Gates to a ship. They run in threads. The idea is to let them run and pause during a random moment in the run method to simulate persons passing. This is done by all threads, meanwhile the main thread is waiting for notification and checking if the ship is getting full when notified by the threads that they added a person passing through the gate the main thread checks again if the ship is full. The program has three classes:
A counter:
public class Counter {
private int currentValue[];
private int maxValue;
public Counter(int[] nrOfPeople, int max) {
currentValue = nrOfPeople;
currentValue[0] = 0;
maxValue = max;
}
public synchronized void addPersons(int nr_p) {
currentValue[0] += nr_p;
}
public synchronized int getValue() {
return currentValue[0];
}
public synchronized boolean isFull() {
if(currentValue[0] < maxValue)
return false;
return true;
}
}
A Gate Class:
public abstract class Gate implements Runnable {
int nrOfPassengers;
int gatenr;
int gatesize;
Counter c;
private Thread t;
private Random r;
private boolean blocked; /* suspends people from passing */
public Gate(Counter c, int nr) {
this.c = c;
gatenr = nr;
this.open();
r = new Random();
t = new Thread(this);
t.start();
}
public void setGatesize(int size) {
gatesize = size;
}
public void close() {
blocked = true;
}
public void open() {
blocked = false;
}
public int getNoOfPassangers() {
return nrOfPassengers;
}
public int getId() {
return gatenr;
}
#Override
public void run() {
while(!blocked) {
int waitTime = (r.nextInt(5) + 1) * 1000; /* between 1-5 seconds */
System.out.println("Person-Gate " + gatenr + ": adding one to " + c.getValue());
try {
/* bigger throughput => amount can vary */
if(gatesize > 1) {
int persons = r.nextInt(gatesize)+1;
c.addPersons(persons);
nrOfPassengers += persons;
} else {
c.addPersons(1);
nrOfPassengers++;
}
Thread.sleep(waitTime);
} catch (InterruptedException e) {
System.out.println("Person-Gate " + gatenr + ": was interrupted adding person");
e.printStackTrace();
}
System.out.println("Person-Gate " + gatenr + ": added one to " + c.getValue());
t.notify();
}
}
public void join() {
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
And a Simulator that runs the main method:
/*
* This class simulates cars and persons- entering a ferry.
*/
public class Simulator {
public static final int MAX = 30;
public static void main(String[] args) {
int nrOfPeople[] = new int[1]; /* array of size one for keeping count */
ArrayList<Gate> gates = new ArrayList<Gate>();
Counter counter = new Counter(nrOfPeople, MAX);
Thread mainThread = Thread.currentThread();
/* adding 3 person-gates */
for(int i=1; i<4; i++) {
gates.add(new PersonGate(counter, i));
}
/* let all gates work as long as passengers is under MAX */
while(!counter.isFull()) {
try {
mainThread.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("Announcement: Ship is full!");
/* wait for child threads to finish */
for(Gate g: gates) {
g.close();
try {
g.join();
} catch (Exception e) { /* InterruptedException */
e.printStackTrace();
}
System.out.println(g.getNoOfPassangers() + " passed through gate nr " + g.getId());
System.out.println(counter.getValue() + " has passed in total");
}
}
}
Im getting a error
Person-Gate 1: adding one to 0
Person-Gate 2: adding one to 1
Person-Gate 3: adding one to 2
Exception in thread "main" java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:485)
at Simulator.main(Simulator.java:24)
Person-Gate 3: added one to 3Exception in thread "Thread-3"
Does anyone now whats going on?
You can only call wait and notify/notifyAll from within synchronized blocks.
t.notify();
You are notifying wrong monitor. This exception occurs, when you do not wrap monitor object with synchronize section. However, objects which you are using for notify and for wait methods are different. Create new Object() monitor and pass it to the constructor of Gate.
Also you can take a look at CountDownLatch, it does exactly what you are trying to achieve.
You must own the monitor of the object on which you call wait or notify. Meaning, you must be in a synchonize-Block, like
synchronized( objectUsedAsSynchronizer) {
while ( mustStillWait) {
objectUsedAsSynchronizer.wait();
}
}
This has been the subject of many other questions.

Categories