Why will the CPU time be different without using volatile? - java

Code 1: In this code, I use the System.out.println(); to get the value changed by other thread instead of using volatile.
package edu.seu.juc.vol;
import edu.seu.juc.annotation.ThreadNotSafe;
import java.lang.management.ManagementFactory;
/**
* #author: zs.sun
* Create at: 2020/5/24 10:31
* #Package: edu.seu.juc.vol
* #ProjectName: af-study
* #Description:
*/
#ThreadNotSafe
public class TestVolatile01 {
public static void main(String[] args) {
Long startTime = System.currentTimeMillis();
ThreadDemo td = new ThreadDemo();
new Thread(td).start();
while (true) {
if (td.isFlag()) {
System.out.println("--------------------------");
break;
}
System.out.println(); // to see the value changed by other thread
}
System.out.println("total: " + (System.currentTimeMillis() - startTime));
System.out.println("CPU time: " + ManagementFactory.getThreadMXBean().getThreadCpuTime(Thread.currentThread().getId())
/ (1000 * 1000));
}
private static class ThreadDemo implements Runnable {
private boolean flag = false;
#Override
public void run() {
try {
Thread.sleep(2000);
flag = true;
System.out.println("flag = " + isFlag());
} catch (Exception e) {
e.printStackTrace();
}
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
}
Result1
...(some blank lines)
flag = true
--------------------------
total: 2010
CPU time: 875
Code 2: In this code, I use the volatile to get the value changed by other thread.
package edu.seu.juc.vol;
import edu.seu.juc.annotation.ThreadSafe;
import java.lang.management.ManagementFactory;
/**
* #author: zs.sun
* Create at: 2020/5/24 10:31
* #Package: edu.seu.juc.vol
* #ProjectName: af-study
* #Description:
*/
#ThreadSafe
public class TestVolatile02 {
public static void main(String[] args) {
Long startTime = System.currentTimeMillis();
ThreadDemo td = new ThreadDemo();
new Thread(td).start();
while (true) {
if (td.isFlag()) {
System.out.println("--------------------------");
break;
}
}
System.out.println("total: " + (System.currentTimeMillis() - startTime));
System.out.println("CPU time: " + ManagementFactory.getThreadMXBean().getThreadCpuTime(Thread.currentThread().getId())
/ (1000 * 1000));
}
private static class ThreadDemo implements Runnable {
private volatile boolean flag = false;
#Override
public void run() {
try {
Thread.sleep(2000);
flag = true;
System.out.println("flag = " + isFlag());
} catch (Exception e) {
e.printStackTrace();
}
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
}
Result 2
--------------------------
total: 2005
flag = true
CPU time: 1968
Can anyone tell me why the CPU time is different?
In my opinion, the main thread in both Codes keeps the CPU all the time, but the Code 1 keeps the absolutely less CPU time.

In Code 1, time spent in the OS Kernel to print the blank line (and maybe scroll the terminal window), is time not spent in the Java thread, so not all the CPU time is counted when printing.
The loop in Code 2 is a pure CPU loop, so all the time is spent by the Java thread.

Related

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.

java multi-thread acquire lock not working

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.

Java Semaphore Acquire Order Based on Thread Value

Good afternoon everyone,
I am working on a school project that requires me to use semaphores to control access to resources. From what I have developed so far, they are:
Semaphore 1) Waiting Area - This permits only 15 customers (Threads) to enter the waiting area, else they are rejected from the store (using TryAcquire).
Semaphore 2) ServerQueue - This permits customers (Threads) to use the only 3 servers in the restaurant once in the waiting area.
My Problem: Our professor requires the serverQueue to take the shortest order (IE, the thread with the least amount of burritosOrdered) when in the waitingArea.
Full flow of application:
Main method instantiates a serverQueue (3 servers) and a waitingArea (15 customers)
Main method instantiates and starts 20 customer threads
Each customer (Thread) run function has been overridden to attempt to get in the waiting area
Each customer in the waitingArea tries to access a server in the serverQueue
How can I tell the serverQueue to get the shortest order? Because the threads override the run, I don't have direct access to an array of all the threads to compare their values.
Thank you for taking a look!
Main
public class Main {
private static final int numCustomers = 5;
public static void main(String[] args)
{
ServerQueue serverQueue = new ServerQueue();
WaitingArea waitingArea = new WaitingArea(3, serverQueue);
Thread customers[] = new Thread[numCustomers];
for (int i = 0; i < numCustomers; i++)
{
customers[i] = new Thread(new Customer(waitingArea), "Customer " + i);
}
for (int i = 0; i < numCustomers; i++)
{
customers[i].start();
}
}
}
Customer
import java.util.Date;
import java.util.Random;
// Runnable is an interface that facilitates threads
public class Customer implements Runnable {
// The semaphore
// private ServerQueue serverQueue;
private WaitingArea waitingArea;
public int burritosOrdered;
public int burritosMade = 0;
// Constructor, allow semaphore to be passed/assigned
public Customer(WaitingArea waitingArea) {
this.waitingArea = waitingArea;
Random r = new Random();
this.burritosOrdered = r.nextInt(21);
}
public void setBurritosMade(int newBurritos) {
this.burritosMade += newBurritos;
}
// We must override the run function within Runnable
// The run function is called by threadObject.start();
#Override
public void run() {
waitingArea.seatCustomer(burritosOrdered);
}
}
waitingArea
import java.util.Date;
import java.util.concurrent.Semaphore;
public class WaitingArea {
private Semaphore semaphore;
private ServerQueue serverQueue;
private int maxCustomers;
public WaitingArea(int maxCustomers, ServerQueue serverQueue) {
semaphore = new Semaphore(maxCustomers, true);
this.serverQueue = serverQueue;
this.maxCustomers = maxCustomers;
}
public void seatCustomer(int burritosOrdered)
{
boolean hasPermit = false;
try
{
hasPermit = semaphore.tryAcquire();
if(hasPermit) {
System.out.println(new Date() + " - "
+ Thread.currentThread().getName()
+ " entered store ordering "
+ burritosOrdered + " burritos");
serverQueue.finishOrder();
} else {
System.out.println(new Date() + " - " + Thread.currentThread().getName() + " left due to full shop");
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
if(hasPermit) {
semaphore.release();
System.out.println(new Date() + " - "
+ Thread.currentThread().getName()
+ " left with " + burritosOrdered + " burritos made");
}
}
}
}
serverQueue
import java.util.Date;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ServerQueue {
// This Semaphore will keep track of no. of servers used at any point.
private final Semaphore semaphore;
// While checking/acquiring a free server out of three available servers, we will use this lock.
private final Lock serverLock;
// This array represents the pool of free server.
private boolean freeServers[];
public ServerQueue() {
semaphore = new Semaphore(1, true);
freeServers = new boolean[1];
serverLock = new ReentrantLock();
// Set all servers to available
for(int i=0;i<freeServers.length;i++) {
freeServers[i] = true;
}
}
public void finishOrder() throws InterruptedException {
try {
System.out.println(semaphore.getClass());
// Decrease the semaphore counter to mark a printer busy
semaphore.acquire();
// Get the server printer
int assignedServer = getServer();
Thread.sleep(3000);
// Print the job
System.out.println(new Date() + " - " + Thread.currentThread().getName()
+ " is getting service from server " + assignedServer);
//Server is done; Free the server to be used by other threads.
releaseServer(assignedServer);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.print(new Date() + " - " + Thread.currentThread().getName() + " has been served\n");
//Increase the semaphore counter back
semaphore.release();
}
}
//Acquire a free server to finish a job
private int getServer() {
int foundServer = -1;
try {
//Get a lock here so that only one thread can go beyond this at a time
serverLock.lock();
//Check which server is free
for (int i=0; i<freeServers.length; i++)
{
//If free server found then mark it busy
if (freeServers[i])
{
foundServer = i;
freeServers[i] = false;
break;
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//Allow other threads to check for free servers
serverLock.unlock();
}
return foundServer;
}
//Release the server
private void releaseServer(int i) {
serverLock.lock();
//Mark the server as free
freeServers[i] = true;
serverLock.unlock();
}
}

Java - Multithreads exercise

I have to solve an homework, this is the question:
Look this program, run it and found the problem then fix it.
this is the program:
package serie02;
import java.util.ArrayList;
class S2Es1Timer {
private long startTime = -1;
private long stopTime = -1;
final protected void start() {
startTime = System.currentTimeMillis();
}
final protected void stop() {
stopTime = System.currentTimeMillis();
}
final public long getElapsedTime() {
if (startTime < 0 || stopTime < 0)
return 0;
return stopTime - startTime;
}
}
class S2Es1SharedState {
boolean sharedState = false;
}
class S2Es1Worker implements Runnable {
private static final long START_VALUE = 1000000000;
private final int id;
private final S2Es1Timer timer;
private final S2Es1SharedState state;
private long localCounter = START_VALUE;
public S2Es1Worker(final int id, final S2Es1SharedState state) {
this.id = id;
timer = new S2Es1Timer();
this.state = state;
log("created");
}
#Override
public void run() {
timer.start();
while (--localCounter > 0) {
if (state.sharedState) {
timer.stop();
log("sharedState has already been set by another worker. localCounter: "
+ ((100.0 * localCounter) / START_VALUE)
+ " % from goal");
return;
}
}
// richiedi accesso esclusivo per scrittura
state.sharedState = true;
timer.stop();
log("sharedState has been set");
}
final protected void log(final String s) {
System.out.println(this.getClass().getSimpleName() + id + ": " + s);
}
final protected void logElapseTime() {
log("time: " + timer.getElapsedTime() + " ms");
}
}
public class S2Esercizio1 {
private final static int NUM_WORKERS = 10;
public static void main(final String[] args) {
final S2Es1Timer mainTimer = new S2Es1Timer();
final ArrayList<Thread> threads = new ArrayList<Thread>();
final ArrayList<S2Es1Worker> workers = new ArrayList<S2Es1Worker>();
final S2Es1SharedState myShare = new S2Es1SharedState();
// Crea 10 Workers
for (int i = 0; i < NUM_WORKERS; i++) {
final S2Es1Worker worker = new S2Es1Worker(i, myShare);
workers.add(worker);
threads.add(new Thread(worker));
}
System.out.println("Simulation started");
System.out.println("------------------------------------");
mainTimer.start();
// Fa partire tutte le threads
for (final Thread t : threads)
t.start();
try {
// Attende che tutte le threads terminano
for (final Thread t : threads)
t.join();
} catch (final InterruptedException e) {
/* Unhandled exception */
}
mainTimer.stop();
System.out.println("------------------------------------");
for (final S2Es1Worker worker : workers)
worker.logElapseTime();
System.out.println("Simulation time: " + mainTimer.getElapsedTime()
+ " ms");
System.out.println("Simulation finished");
}
}
this is the output:
S2Es1Worker0: created
S2Es1Worker1: created
S2Es1Worker2: created
S2Es1Worker3: created
S2Es1Worker4: created
S2Es1Worker5: created
S2Es1Worker6: created
S2Es1Worker7: created
S2Es1Worker8: created
S2Es1Worker9: created
Simulation started
------------------------------------
S2Es1Worker6: sharedState has been set
S2Es1Worker7: sharedState has been set
S2Es1Worker3: sharedState has been set
S2Es1Worker5: sharedState has been set
S2Es1Worker9: sharedState has been set
S2Es1Worker0: sharedState has been set
S2Es1Worker4: sharedState has been set
S2Es1Worker8: sharedState has been set
S2Es1Worker1: sharedState has been set
S2Es1Worker2: sharedState has been set
------------------------------------
S2Es1Worker0: time: 2300 ms
S2Es1Worker1: time: 2401 ms
S2Es1Worker2: time: 2420 ms
S2Es1Worker3: time: 1921 ms
S2Es1Worker4: time: 2332 ms
S2Es1Worker5: time: 2169 ms
S2Es1Worker6: time: 909 ms
S2Es1Worker7: time: 1847 ms
S2Es1Worker8: time: 2305 ms
S2Es1Worker9: time: 2237 ms
Simulation time: 2422 ms
Simulation finished
I think is a problem of visibility, i mean when the first thread finish the loop and set the shared mutable variable sharedState to true, the others threads continue to loop because they have a "dirty read" in the cache cpu (i have 4 cpu).
So the only good thing that i can do is set the sharedState variable with the key volatile. in this way every thread reads the correct value. I lost time because this value now is catched by the main memory instead of the cpu cache.
Another solution could be: to use ReentrantReadWriteLock.
So the class S2Es1SharedState could be writed in this way:
class S2Es1SharedState {
private final ReadWriteLock lock = new ReentrantReadWriteLock();
private final Lock readLock = lock.readLock();
private final Lock writeLock = lock.writeLock();
boolean sharedState = false;
public boolean getSharedState() {
readLock.lock();
try {
return sharedState;
} finally {
readLock.unlock();
}
}
public void setSharedState() {
writeLock.lock();
try {
this.sharedState = true;
}
finally {
writeLock.unlock();
}
}
}
This solution i think work because the lock also give a correct visibility but i think take a lot of time because in this way inside the loop i don't use the cache cpu but just the main memory. and this operation need time.
I'm not sure about my analysis, for this reason i prefer to ask to 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