java multi-thread acquire lock not working - java

I'm trying to write a small snippet of code to lock and unlock a block of code.
the acquire_lock and release_lock functions are as below:
public static void acquire_lock(long timestamp) {
synchronized(operations) {
// put the timestamp into queue
operations.add(timestamp);
// check if the head of queue is current timestamp, if not,
// this means there are some other operations ahead of current one
// so current operation has to wait
while (operations.peek() != timestamp) {
try {
operations.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void release_lock() {
synchronized(operations) {
// poll the finished operation out of queue
// and wake up all waiting operations
operations.poll();
operations.notifyAll();
}
}
But when I put this code into a test environment, it doesn't always work well,
the whole test code is as below:
public class AcquireLockNotWork {
static int balance = 0;
static PriorityQueue<Long> operations = new PriorityQueue<Long>();
// withdraw money from balance
public static void withdraw(final int amt) {
// get system time
Long timestamp = System.nanoTime();
Thread t = new Thread(new Runnable() {
public void run() {
// try to use acquire_lock to lock this piece of code
acquire_lock(timestamp);
try {
Thread.sleep(500);
int holdings = balance;
balance = holdings - amt;
System.out.println("Withdrew " + amt + " from funds. Now at " + balance);
} catch (Exception e) {
e.printStackTrace();
} finally {
release_lock();
}
}
});
t.start();
}
//put money into banlance
public static void deposit(int amt) {
Thread t1 = new Thread(new Runnable() {
public void run() {
Long timestamp = System.nanoTime();
acquire_lock(timestamp);
int holdings = balance;
balance = holdings + amt;
System.out.println("deposit " + amt + ", balance: " + balance);
release_lock();
}
});
t1.start();
}
public static void acquire_lock(long timestamp) {
synchronized(operations) {
// put the timestamp into queue
operations.add(timestamp);
// check if the head of queue is current timestamp, if not,
// this means there are some other operations ahead of current one
// so current operation has to wait
while (operations.peek() != timestamp) {
try {
operations.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void release_lock() {
synchronized(operations) {
// poll the finished operation out of queue
// and wake up all waiting operations
operations.poll();
operations.notifyAll();
}
}
public static void test1() {
balance = 0;
deposit(2000);
withdraw(500);
withdraw(1000);
}
public static void main(String[] args) {
test1();
}
}
for a small number of times, the result will be like this:
deposit 2000, balance: 2000
Withdrew 500 from funds. Now at 500
Withdrew 1000 from funds. Now at 500
which means that the acquire_lock and release_lock function doesn't work well. It seems that the last two thread (withdrew 500 and withdrew 1000) has entered the block between acquire_lock() and release_lock() simultaneously, and it is not what I want.
So what's wrong with the acquire_lock and release_lock function?

It is very tricky here.
The anomalous happens because the latter thread enter the acquire_lock first. And when the earlier thread goes into the acquire_lock, it will not be blocked, because the code block the threads based on their timestamp. So the two thread go to the same protected code area.

Related

Correct way to take from queue?

The code below randomly freezing.
The queue is pre-filled at the start and only taken from after the threads start taking items from it.
I think I'm not using the queue properly. Despite the isEmpty() check, the queue might be empty when one thread tries to take one item, making it to wait indefinitely.
#Override
public void run() {
long milisecs;
try {
while ( ! queue.isEmpty()) { // !!!
milisecs = queue.take(); // !!!
worker(milisecs);
}
} catch (InterruptedException ex) {}
}
For example, it would hang is this scenario happens:
threadA checks if queue.isEmpty(), gets a false and tries to proceed.
threadB take() the last item from the queue
threadA tries to take() an item from an empty queue, making it to hang.
The process "take if queue not empty" should be synched so that the queue doesn't change in between.
What is the proper way to do that?
Full code below. Should take about 1s per run.
package multithreadperformance;
import java.util.ArrayList;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadLocalRandom;
public class MultithreadPerformance implements Runnable {
static int numThreads = 50;
static int numJobs = 5000;
final BlockingQueue<Long> queue = new LinkedBlockingQueue<>();;
static ArrayList<Thread> threads;
public static void main(String[] args) {
MultithreadPerformance bench = new MultithreadPerformance();
bench.go();
}
public void go() {
System.out.print("Go... ");
long t0 = System.nanoTime();
// Fill up the queue of jobs with a random number of miliseconds.
long milisecs, milisecsMax = 20; // ms
//
try {
for (int i = 0; i < numJobs; i++) {
milisecs = ThreadLocalRandom.current().nextLong(milisecsMax);
queue.put(milisecs);
}
} catch (InterruptedException ex) {
System.out.println(ex.toString());
}
// Create all threads
threads = new ArrayList<>();
for(int i = 0; i < numThreads; i++) {
Thread thread = new Thread(this);
thread.setName("Thread" + i);
threads.add(thread);
}
// Start all threads
threads.forEach((thread) -> {thread.start();});
// Join all threads
threads.forEach((thread) -> {try {
thread.join();
} catch (InterruptedException ex) {
System.out.println(ex.toString());
}
});
long et = System.nanoTime() - t0;
System.out.println(String.format("done. Elapsed time %.3f s.", et/1e9));
}
// Worker function
// Sleep a number of miliseconds.
public void worker(long milisecs) throws InterruptedException {
Thread.sleep(milisecs);
}
#Override
public void run() {
long milisecs;
try {
while ( ! queue.isEmpty()) {
milisecs = queue.take();
worker(milisecs);
}
} catch (InterruptedException ex) {
System.out.println(ex.toString());
}
}
}
You could call poll() which will atomically remove the head of the queue or return null if the queue was empty.
Long millisecs;
while ( (millisecs = queue.poll()) != null) {
worker(millisecs);
}
Just have the worker threads block on the queue. When you're done, put n End-Of-Queue messages in the queue with n the number of worker threads and have the worker threads exit their loop when they see an End-Of-Queue message.

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.

Using CountDownLatch & Object.wait inside recursive block hangs

Problem: While trying to retrieve values inside a recursive block in a phased manner, the execution gets hung.
Description: CountDownLatch & Object.wait are used to achieve the phased manner access of value inside the recursive block. But, the program hangs with following output:
2 < 16
3 < 16
4 < 16
5 < 16
Current total: 5
Inside of wait
Inside of wait
Program:
import java.util.concurrent.*;
public class RecursiveTotalFinder {
private static CountDownLatch latch1;
private static CountDownLatch latch2;
private static CountDownLatch latch3;
public static void main(String... args) {
latch1 = new CountDownLatch(1);
latch2 = new CountDownLatch(1);
latch3 = new CountDownLatch(1);
//Create object
TotalFinder tf = new TotalFinder(latch1,latch2,latch3);
//Start the thread
tf.start();
//Wait for results from TotalFinder
try {
latch1.await();
} catch(InterruptedException ie) {
ie.printStackTrace();
}
//Print the result after 5th iteration
System.out.println("Current total: "+tf.getCurrentTotal());
tf.releaseWaitLock();
tf.resetWaitLock();
//Wait for results again
try {
latch2.await();
} catch(InterruptedException ie) {
ie.printStackTrace();
}
//Print the result after 10th iteration
System.out.println("Current total: "+tf.getCurrentTotal());
tf.releaseWaitLock();
tf.resetWaitLock();
//Wait for results again
try {
latch3.await();
} catch(InterruptedException ie) {
ie.printStackTrace();
}
//Print the result after 15th iteration
System.out.println("Current total: "+tf.getCurrentTotal());
tf.releaseWaitLock();
tf.resetWaitLock();
}
}
class TotalFinder extends Thread{
CountDownLatch tfLatch1;
CountDownLatch tfLatch2;
CountDownLatch tfLatch3;
private static int count = 1;
private static final class Lock { }
private final Object lock = new Lock();
private boolean gotSignalFromMaster = false;
public TotalFinder(CountDownLatch latch1, CountDownLatch latch2,
CountDownLatch latch3) {
tfLatch1 = latch1;
tfLatch2 = latch2;
tfLatch3 = latch3;
}
public void run() {
findTotal(16);
}
//Find total
synchronized void findTotal(int cnt) {
if(count%5==0) {
if(count==5)
tfLatch1.countDown();
if(count==10)
tfLatch2.countDown();
if(count==15)
tfLatch3.countDown();
//Sleep for sometime
try {
Thread.sleep(3000);
} catch(InterruptedException ie) {
ie.printStackTrace();
}
//Wait till current total is printed
synchronized(lock) {
while(gotSignalFromMaster==false) {
try {
System.out.println(" Inside of wait");
lock.wait();
} catch(InterruptedException ie) {
ie.printStackTrace();
}
}
System.out.println("Came outside of wait");
}
}
count +=1;
if(count < cnt) {
System.out.println(count +" < "+cnt);
findTotal(cnt);
}
}
//Return the count value
public int getCurrentTotal() {
return count;
}
//Release lock
public void releaseWaitLock() {
//Sleep for sometime
try {
Thread.sleep(5000);
} catch(InterruptedException ie) {
ie.printStackTrace();
}
synchronized(lock) {
gotSignalFromMaster=true;
lock.notifyAll();
}
}
//Reset wait lock
public void resetWaitLock() {
gotSignalFromMaster = false;
}
}
Analysis:
In my initial analysis it looks like the wait is happening recursively eventhough notifyAll is invoked from the main program.
Help:
Why free lock using notfiyAll after a CountDownLatch didn't take effect? Need someone's help in understanding what exactly is happening in this program.
The main message about wait and notify that I got from JCIP was that I'd probably use them wrongly, so better to avoid using them directly unless strictly necessary. As such, I think that you should reconsider the use of these methods.
In this case, I think that you can do it more elegantly using SynchronousQueue. Perhaps something like this might work:
import java.util.concurrent.*;
public class RecursiveTotalFinder {
public static void main(String... args) throws InterruptedException {
SynchronousQueue<Integer> syncQueue = new SynchronousQueue<>();
//Create object
TotalFinder tf = new TotalFinder(syncQueue, 5);
//Start the thread
tf.start();
for (int i = 0; i < 3; ++i) {
System.out.println("Current total: " + syncQueue.take());
}
}
}
class TotalFinder extends Thread{
private final SynchronousQueue<Integer> syncQueue;
private final int syncEvery;
private int count;
public TotalFinder(SynchronousQueue<Integer> syncQueue,
int syncEvery) {
this.syncQueue = syncQueue;
this.syncEvery = syncEvery;
}
public void run() {
try {
findTotal(16);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
}
//Find total
void findTotal(int cnt) throws InterruptedException {
if((count > 0) && (count%syncEvery==0)) {
syncQueue.put(count);
}
count +=1;
if(count < cnt) {
System.out.println(count +" < "+cnt);
findTotal(cnt);
}
}
}
As to why your original approach doesn't work, it's because the main thread sets gotSignalFromMaster to true and then immediately back to false, and this happens before the other thread is able to check its value. If you stick a bit of a sleep into the resetWaitLock, it proceeds beyond the point where it currently hangs; however, it then hangs at the end instead of terminating.
Note that having to use Thread.sleep to wait for another thread to change some state is a poor approach - not least because it makes your program really slow. Using synchronization utilities leads to faster and much easier-to-reason-about program.

Java looping Threads using CyclicBarrier

I have a program with this general structure:
init
create CyclicBarrier
initialise all threads, attaching to barrier
*start all threads*
wait for join
display stats
*start all threads*
perform calculation
await barrier
My problem is I need the threads' run() method to keep looping until a certain condition is met, but pausing after every iteration to let all threads synchronise.
I've already tried attaching a Runnable method to the barrier, but this ends up requiring the recreation and restarting of each thread, which isn't a very good solution.
I've also tried using the CyclicBarrier's reset() method, but this just seems to cause errors on the existing threads, even when executed after all threads have completed.
My question is:
-Is it possible to 'reset' a barrier and have all the barrier's threads follow the same conditions as they did before the first invocations of await()?
-Or is there another method I should be using to achieve this?
Thanks in advance
The barrier.wait() will suspend the threads. The barrier is already in the main thread, it does not need another. In your algorithm above you show the threads being restarted after displaying stats. You should not need to do this. If the recently awakened threads are in a loop they will go back into the barrier.wait() again.
Following #Totoro's answer, below is a little bit of example code which also incorporates the requirement "I need the threads' run() method to keep looping until a certain condition is met, pausing after every iteration to let all threads synchronise". That makes it complex pretty quick, but hopefully the program output will clarify the example code (or I should just make better examples).
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
public class BarrierCalc implements Runnable {
public static final int CALC_THREADS = 3;
private static final AtomicBoolean runCondition = new AtomicBoolean();
private static final AtomicBoolean stopRunning = new AtomicBoolean();
public static void main(String[] args) {
CyclicBarrier barrier = new CyclicBarrier(CALC_THREADS + 1);
for (int i = 0; i < CALC_THREADS; i++) {
new Thread(new BarrierCalc(barrier)).start();
}
try {
runCondition.set(true);
barrier.await();
showln(0, "STATS!");
barrier.await();
showln(0, "start looping 1");
Thread.sleep(200);
runCondition.set(false);
showln(0, "stop looping 1");
barrier.await();
runCondition.set(true);
barrier.await();
showln(0, "start looping 2");
Thread.sleep(100);
runCondition.set(false);
showln(0, "stop looping 2");
barrier.await();
stopRunning.set(true);
showln(0, "finishing");
barrier.await();
} catch (Exception e) {
e.printStackTrace();
}
}
private static final AtomicInteger calcId = new AtomicInteger();
private CyclicBarrier barrier;
private int id;
public BarrierCalc(CyclicBarrier barrier) {
this.barrier = barrier;
id = calcId.incrementAndGet();
}
public void run() {
showln(id, "waiting for start");
try {
barrier.await(); // display stats
barrier.await(); // start running
int loopNumber = 0;
while (!stopRunning.get()) {
showln(id, "looping " + (++loopNumber));
while (runCondition.get()) {
Thread.sleep(10); // simulate looping
}
showln(id, "synchronizing " + loopNumber);
barrier.await();
showln(id, "synchronized " + loopNumber);
// give main thread a chance to set stopCondition and runCondition
barrier.await();
}
showln(id, "finished");
} catch (Exception e) {
e.printStackTrace();
}
}
private static final long START_TIME = System.currentTimeMillis();
public static void showln(int id, String msg) {
System.out.println((System.currentTimeMillis() - START_TIME) + "\t ID " + id + ": " + msg);
}
}
Keep in mind that program output might not be in the order expected: threads that are writing at the same time to one synchronized output (System.out) are given write-access in random order.
You can take a look at my example where I played with CyclicBarrier.Here each worker makes some calculation and at the barrier the condition is checked. If it meets the condition than all workers stop calculations, otherwise they continue:
class Solver {
private static final int REQUIRED_AMOUNT = 100;
private static final int NUMBER_OF_THREADS = 4;
AtomicInteger atomicInteger = new AtomicInteger();
AtomicBoolean continueCalculation = new AtomicBoolean(true);
final CyclicBarrier barrier;
public static void main(String[] args) {
new Solver();
}
class Worker implements Runnable {
int workerId;
Worker(int workerId) {
this.workerId = workerId;
}
public void run() {
try {
while(continueCalculation.get()) {
calculate(workerId);
barrier.await();
}
} catch (Exception ex) {
System.out.println("Finishing " + workerId);
}
}
}
public Solver() {
Runnable barrierAction = () -> {
if (done()) {
continueCalculation.set(false);
}
};
barrier = new CyclicBarrier(NUMBER_OF_THREADS, barrierAction);
List<Thread> threads = new ArrayList(NUMBER_OF_THREADS);
for (int i = 0; i < NUMBER_OF_THREADS; i++) {
Thread thread = new Thread(new Worker(i));
threads.add(thread);
thread.start();
}
}
private void calculate(int workerId) throws InterruptedException {
// Some long-running calculation
Thread.sleep(2000L);
int r = new Random().nextInt(12);
System.out.println("Worker #" + workerId + " added " + r +" = " + atomicInteger.addAndGet(r));
}
private boolean done() {
int currentResult = atomicInteger.get();
boolean collected = currentResult >= REQUIRED_AMOUNT;
System.out.println("=======================================================");
System.out.println("Checking state at the barrier: " + currentResult);
if (collected) {
System.out.println("Required result is reached");
}
System.out.println("=======================================================");
return collected;
}
}

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