import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.atomic.AtomicBoolean;

public class LivelockSimulasi {
    private static final int MAKS_RONDE = 10;

    // Pembungkus agar loop tidak perlu menangani exception barrier secara langsung.
    private static void tunggu(CyclicBarrier pagar) {
        try {
            pagar.await();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } catch (Exception e) {
            // BrokenBarrierException tidak mungkin terjadi pada simulasi ini.
        }
    }

    // Satu ronde ritual sopan-santun: pasang niat, baca niat lawan,
    // lalu mundur bila lawan juga ingin lewat. Tiga pagar memastikan
    // kedua thread selalu membaca niat lawan dalam keadaan terpasang.
    private static void jalankan(AtomicBoolean niatSendiri,
            AtomicBoolean niatLawan, CyclicBarrier pagar, int[] rondeTerpakai) {
        for (int ronde = 1; ronde <= MAKS_RONDE; ronde++) {
            niatSendiri.set(true); // pasang niat untuk ronde ini
            tunggu(pagar);         // pagar-1: niat kedua pihak terpasang

            boolean lawanJugaMau = niatLawan.get();
            tunggu(pagar);         // pagar-2: kedua pihak sudah selesai membaca

            if (lawanJugaMau) {
                niatSendiri.set(false); // lawan ingin lewat: mundur sopan
            }
            tunggu(pagar);         // pagar-3: keputusan ronde terekam
            rondeTerpakai[0] = ronde;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        AtomicBoolean budiMau = new AtomicBoolean(true);
        AtomicBoolean sitiMau = new AtomicBoolean(true);
        CyclicBarrier pagar = new CyclicBarrier(2); // menyamakan irama kedua thread
        int[] rondeBudi = new int[1];
        int[] rondeSiti = new int[1];

        Thread budi = new Thread(
                () -> jalankan(budiMau, sitiMau, pagar, rondeBudi), "Budi");
        Thread siti = new Thread(
                () -> jalankan(sitiMau, budiMau, pagar, rondeSiti), "Siti");

        budi.start();
        siti.start();
        budi.join();
        siti.join();

        System.out.println("Budi menjalani " + rondeBudi[0] + " ronde tanpa pernah maju");
        System.out.println("Siti menjalani " + rondeSiti[0] + " ronde tanpa pernah maju");
        System.out.println("kedua thread aktif sampai akhir, koridor tak pernah dilewati");
    }
}
