// Exercise 1: synchronized fixes a race condition (easy/medium)
//
// SafeCounter below is NOT thread-safe — increment() is a plain count++.
// TODO 1: add `synchronized` to increment() and get() so both are
//         mutually exclusive on the same lock (`this`).
//
// The self-check spins up MANY threads, each incrementing the SAME
// SafeCounter instance many times concurrently, then joins all of them
// and asserts the final count is EXACTLY threads * incrementsPerThread —
// only possible if increment() is properly synchronized.

public class java_concurrency_basics_exercise_1 {

    static class SafeCounter {
        private int count = 0;

        // TODO 1: make this method synchronized
        void increment() {
            count++;
        }

        // TODO 1: make this method synchronized
        int get() {
            return count;
        }
    }

    // --- self-check: do not modify below this line ---
    public static void main(String[] args) throws InterruptedException {
        boolean ok = true;

        int threads = 8;
        int incrementsPerThread = 10_000;
        SafeCounter counter = new SafeCounter();

        Thread[] pool = new Thread[threads];
        for (int i = 0; i < threads; i++) {
            pool[i] = new Thread(() -> {
                for (int j = 0; j < incrementsPerThread; j++) {
                    counter.increment();
                }
            });
        }

        for (Thread t : pool) t.start();
        for (Thread t : pool) t.join(); // wait for every thread to finish before checking

        int expected = threads * incrementsPerThread;
        ok &= counter.get() == expected;
        if (!ok) {
            System.out.println("expected " + expected + " but got " + counter.get() + " (lost updates -> not synchronized)");
        }

        System.out.println(ok ? "PASS" : "FAIL");
    }
}
