Cigarette Smoker’s Problem

Ich brauche Ihre Hilfe, ich komme immer zu Deadlock, kann jemand mir bitte helfen?

public class RaucherProblemDeadlock {

    static RaucherMitTabak tabakRaucher = new RaucherMitTabak();
    static RaucherMitPapier papierRaucher = new RaucherMitPapier();
    static RaucherMitStreichhoelzern holzRaucher = new RaucherMitStreichhoelzern();
    static Agent agent = new Agent();

    static Semaphor tabakAufTisch = new Semaphor(0);
    static Semaphor papierAufTisch = new Semaphor(0);
    static Semaphor holzAufTisch = new Semaphor(0);
    static Semaphor tischLeer = new Semaphor(1);

    public static void main(String[] args) {
        tabakRaucher.start();
        papierRaucher.start();
        holzRaucher.start();
        agent.start();
    }

    static class RaucherMitTabak extends Thread {
        @Override
        public void run() {
            while (true) {
                papierAufTisch.p();
                holzAufTisch.p();
                System.out.println("Raucher mit Tabak raucht");
                tischLeer.v();
            }
        }
    }

    static class RaucherMitPapier extends Thread {
        @Override
        public void run() {
            while (true) {
                tabakAufTisch.p();
                holzAufTisch.p();
                System.out.println("Raucher mit Papier raucht");
                tischLeer.v();
            }
        }
    }

    static class RaucherMitStreichhoelzern extends Thread {
        @Override
        public void run() {
            while (true) {
                tabakAufTisch.p();
                papierAufTisch.p();
                System.out.println("Raucher mit Streichhoelzern raucht");
                tischLeer.v();
            }
        }
    }

    static class Agent extends Thread {
        @Override
        public void run() {
            while (true) {
                int r = ThreadLocalRandom.current().nextInt(3);
                switch (r) {
                    case 0:
                        tabakAufTisch.v();
                        papierAufTisch.v();
                        break;
                    case 1:
                        tabakAufTisch.v();
                        holzAufTisch.v();
                        break;
                    default:
                        papierAufTisch.v();
                        holzAufTisch.v();
                }
                tischLeer.p();
            }
        }
    }
}