public class q1 {
private volatile boolean frozen;
private volatile boolean overloaded;
private final Object lock = new Object();
private volatile byte state; //use 4 bits to mark each metro count ready
private int sum;
private class OverSeer extends Thread {
private final int capacity;
private final int interval;
public OverSeer(String name, int capacity, int interval) {
super(name);
this.capacity = capacity;
this.interval = interval;
}
@Override
public void run() {
while (true) {
try {
System.out.println(getName() + " freeze");
sum = 0;
state = 0;
frozen = true;
synchronized (lock) {
while (state != 0x0F) {
lock.wait();
}
}
System.out.println(getName() + " sum " + sum);
if (!overloaded) {
if (sum > capacity) {
System.out.println(getName() + " overload, leave only");
overloaded = true;
}
} else {
if (sum < capacity * 0.75) {
overloaded = false;
}
}
System.out.println(getName() + " unfreeze");
sum = 0;
frozen = false;
if (overloaded) {
TimeUnit.MILLISECONDS.sleep(interval / 10);
} else {
TimeUnit.MILLISECONDS.sleep(interval);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
private class Metro extends Thread {
private final Random random = new Random();
private final int offset;
private int count;
public Metro(String name, int offset) {
super(name);
this.offset = offset;
}
@Override
public void run() {
while (true) {
try {
if (!frozen) {
// mock 51% enter, 49% leave
if (random.nextInt(100) < 51) {
if (overloaded) {
System.out.println(getName() + " disallow enter");
} else {
System.out.println(getName() + " enter");
count++;
}
} else {
System.out.println(getName() + " leave");
count--;
}
} else {
synchronized (lock) {
if ((state & (1 << offset)) == 0) {
System.out.println(getName() + " count " + count);
sum += count;
state |= 1 << offset;
if (state == 0x0F) {
lock.notify();
}
}
}
}
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public void start(int capacity, int interval) {
OverSeer overSeer = new OverSeer("overSeer", capacity, interval);
Metro metro1 = new Metro("metro1", 0);
Metro metro2 = new Metro("metro2", 1);
Metro metro3 = new Metro("metro3", 2);
Metro metro4 = new Metro("metro4", 3);
overSeer.start();
metro1.start();
metro2.start();
metro3.start();
metro4.start();
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("Please enter capacity: ");
int capacity = scanner.nextInt();
System.out.println("Please enter interval: ");
int interval = scanner.nextInt();
new q1().start(capacity, interval);
}
}