import java.util.concurrent.locks.ReentrantReadWriteLock;

public class PembacaBersamaan {
    // Flag volatile agar tulisan pembaca-1 langsung terlihat thread lain.
    private static volatile boolean pembaca1DiDalam = false;

    public static void main(String[] args) throws InterruptedException {
        ReentrantReadWriteLock kunci = new ReentrantReadWriteLock();
        boolean[] buktiPembaca = new boolean[1];
        boolean[] buktiPenulis = new boolean[1];

        // pembaca-1 memegang read lock lama (300 ms).
        Thread pembaca1 = new Thread(() -> {
            kunci.readLock().lock();
            try {
                pembaca1DiDalam = true;
                Thread.sleep(300); // pembacaan lambat: read lock tetap bisa dibagi
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } finally {
                pembaca1DiDalam = false;
                kunci.readLock().unlock();
            }
        }, "pembaca-1");

        // pembaca-2 masuk pada ms ke-100, saat pembaca-1 masih memegang read lock.
        Thread pembaca2 = new Thread(() -> {
            try {
                Thread.sleep(100); // pastikan pembaca-1 sudah berada di dalam
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return;
            }
            kunci.readLock().lock(); // BERHASIL: read lock boleh dipegang bersama
            try {
                buktiPembaca[0] = pembaca1DiDalam; // true: pembaca-1 masih di dalam
            } finally {
                kunci.readLock().unlock();
            }
        }, "pembaca-2");

        // penulis mencoba write lock pada ms ke-200, harus menunggu pembaca selesai.
        Thread penulis = new Thread(() -> {
            try {
                Thread.sleep(200); // mulai setelah pembaca-2 selesai membaca
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return;
            }
            kunci.writeLock().lock(); // menunggu sampai read lock benar-benar kosong
            try {
                buktiPenulis[0] = !pembaca1DiDalam; // true: penulis masuk saat bersih
            } finally {
                kunci.writeLock().unlock();
            }
        }, "penulis");

        pembaca1.start();
        pembaca2.start();
        penulis.start();
        pembaca1.join();
        pembaca2.join();
        penulis.join();

        System.out.println("pembaca-2 masuk saat pembaca-1 masih membaca : " + buktiPembaca[0]);
        System.out.println("penulis masuk setelah semua pembaca keluar   : " + buktiPenulis[0]);
    }
}
