Wie es richtig geht... schwierig. Ich würde es mal so skizzieren (eine Richtung):
[code=Java]
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.locks.*;
public class Rail {
public static class Track {
final Lock lock = new ReentrantLock(true);
final Condition greenLights = lock.newCondition();
final Condition left = lock.newCondition();
Queue<Train> trains = new ConcurrentLinkedQueue<>();
Queue<Train> queue = new ConcurrentLinkedQueue<>();
public void occupy(Train train) throws InterruptedException {
queue.add(train); // Reihe den Zug erstmal ein
lock.lock(); // Sperre ab hier
try {
while (trains.size() >= 3) { // wenn bereits drei Züge auf dem Gleis
greenLights.await(); // warte auf eine grüne Ampel
}
trains.add(queue.remove()); // schiebe den nächsten Zug aufs Gleis
} finally {
lock.unlock(); // Sperre in jedem Fall aufheben
}
}
public void leave(Train train) throws InterruptedException {
lock.lock(); // Sperre ab hier
try {
while (trains.peek() != train) {
left.await();
}
Train t = trains.remove(); // nimm den nächsten Zug vom Gleis
greenLights.signal(); // und schalte die Ampel auf "grün"
left.signal();
} finally {
lock.unlock(); // Sperre in jedem Fall aufheben
}
}
}
public static class Train extends Thread {
private final Track track;
private final int delay;
public Train(Track track, int delay) {
this.track = track;
this.delay = delay;
}
public void run() {
try {
System.out.println(getName() + " -> einfahren");
track.occupy(this);
System.out.println(getName() + " -> warte " + delay + " ms");
Thread.sleep(delay);
System.out.println(getName() + " -> verlässt Gleis");
track.leave(this);
System.out.println(getName() + " -> hat Gleis verlassen");
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
public static void main(String[] args) {
Track track = new Track();
for (int i = 0; i < 10; i++) {
new Train(track, (int)(Math.random() * 3000)).start();
}
}
}[/code]