public class SiklusState {
    private static final Object kunci = new Object();

    public static void main(String[] args) throws InterruptedException {
        String[] catatan = new String[5];

        // sleeper: tidur 300 ms, selama itu state-nya TIMED_WAITING.
        Thread sleeper = new Thread(() -> {
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }, "sleeper");

        // worker: memegang lock "kunci" sambil tidur 400 ms.
        Thread worker = new Thread(() -> {
            synchronized (kunci) {
                try {
                    Thread.sleep(400);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }, "worker");

        // waiter: menunggu thread sleeper selesai lewat join tanpa batas waktu.
        Thread waiter = new Thread(() -> {
            try {
                sleeper.join();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }, "waiter");

        // contender: akan mengantre pada lock "kunci" yang sedang dipegang worker.
        Thread contender = new Thread(() -> {
            synchronized (kunci) {
                // masuk ke sini hanya setelah worker melepas kunci
            }
        }, "contender");

        catatan[0] = "sebelum start   : " + worker.getState(); // NEW

        sleeper.start();
        worker.start();
        Thread.sleep(50); // beri waktu worker mengambil kunci dan sleeper mulai tidur

        waiter.start();
        contender.start();
        Thread.sleep(100); // beri waktu contender mengantre dan waiter menunggu

        catatan[1] = "sedang tidur    : " + sleeper.getState();   // TIMED_WAITING
        catatan[2] = "menunggu join   : " + waiter.getState();    // WAITING
        catatan[3] = "mengantre kunci : " + contender.getState(); // BLOCKED

        sleeper.join();
        waiter.join();
        contender.join();
        worker.join();

        catatan[4] = "setelah selesai : " + worker.getState(); // TERMINATED

        for (String baris : catatan) {
            System.out.println(baris);
        }
    }
}
