import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

/** 教师演示：稳定复现更新丢失，再验证原子合并。无外部服务或文件操作。 */
public class ConcurrentMapBoundaryDemo {
    public static void main(String[] args) throws Exception {
        int separated = runCase(false);
        int atomic = runCase(true);
        if (separated != 1 || atomic != 2) {
            throw new IllegalStateException("结果不符：" + separated + ", " + atomic);
        }
        System.out.println("分步更新=" + separated + "，原子合并=" + atomic);
    }

    private static int runCase(boolean useAtomicMerge) throws Exception {
        var counts = new ConcurrentHashMap<String, Integer>();
        counts.put("dept-A", 0);
        var bothReady = new CountDownLatch(2);
        var release = new CountDownLatch(1);
        ExecutorService pool = Executors.newFixedThreadPool(2);
        try {
            Future<?> first = pool.submit(() -> update(counts, bothReady, release, useAtomicMerge));
            Future<?> second = pool.submit(() -> update(counts, bothReady, release, useAtomicMerge));
            if (!bothReady.await(5, TimeUnit.SECONDS)) {
                throw new IllegalStateException("等待两方准备超时");
            }
            release.countDown();
            first.get(5, TimeUnit.SECONDS);
            second.get(5, TimeUnit.SECONDS);
            return counts.get("dept-A");
        } finally {
            release.countDown();
            closePool(pool);
        }
    }

    private static void update(ConcurrentHashMap<String, Integer> counts,
                               CountDownLatch bothReady, CountDownLatch release,
                               boolean useAtomicMerge) {
        // 错误组：先读取旧值，再通过信号确保两方读完才开始写。
        int previous = useAtomicMerge ? 0 : counts.get("dept-A");
        bothReady.countDown();
        try {
            if (!release.await(5, TimeUnit.SECONDS)) {
                throw new IllegalStateException("等待放行超时");
            }
        } catch (InterruptedException interrupted) {
            Thread.currentThread().interrupt();
            throw new IllegalStateException("演示被中断", interrupted);
        }
        if (useAtomicMerge) {
            counts.merge("dept-A", 1, (oldValue, increment) -> oldValue + increment);
        } else {
            counts.put("dept-A", previous + 1);
        }
    }

    private static void closePool(ExecutorService pool) throws InterruptedException {
        pool.shutdown();
        try {
            if (!pool.awaitTermination(5, TimeUnit.SECONDS)) {
                pool.shutdownNow();
                if (!pool.awaitTermination(5, TimeUnit.SECONDS)) {
                    throw new IllegalStateException("演示未按时终止");
                }
            }
        } catch (InterruptedException interrupted) {
            pool.shutdownNow();
            Thread.currentThread().interrupt();
            throw interrupted;
        }
    }
}
