线程安全从Integer到AtomicInteger再到Atom

2019-10-30  本文已影响0人  Watson_ljf

在开发中一些共享变量存在线程安全问题,如何处理。我们通过实验去重现并找到解决方案。

1、直接使用Integer作为共享变量:

public static class Data {
        private volatile Integer date = 0;

        public void addDate() {
            date = date + 1;
        }

        public Integer getDate() {
            return date;
        }
 }

// 实验结果并不是每次都是1000,表明volatile关键字是不能保证线程安全的
private static void 无法保证线程安全() throws InterruptedException {
        Data data = new Data();

        CountDownLatch countDownLatch = new CountDownLatch(10);

        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                for (int j = 0; j < 100; j++) {
                    data.addDate();
                }
            }).start();

            countDownLatch.countDown();
        }

        countDownLatch.await();

        System.out.println("最终计算结果:" + data.getDate());
    }

2、使用AtomicInteger实现线程安全的累加操作。

private static void 保证线程安全但无法处理ABA问题() throws InterruptedException {
        AtomicInteger atomicInteger = new AtomicInteger(0);

        CountDownLatch countDownLatch = new CountDownLatch(10);

        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                for (int j = 0; j < 100; j++) {
                    atomicInteger.incrementAndGet();
                }
            }).start();

            countDownLatch.countDown();
        }

        countDownLatch.await();

        System.out.println("最终计算结果:" + atomicInteger.get());
    }

3、重现AtomicInteger在ABA问题下CAS验证通过的情况。

private static void CAS验证通过表明AtomicInteger无法保证ABA问题() throws InterruptedException {
        AtomicInteger atomicInteger = new AtomicInteger(100);

        Thread thread1 = new Thread(() -> {
            atomicInteger.compareAndSet(100, 101);
            atomicInteger.compareAndSet(101, 100);
        });

        Thread thread2 = new Thread(() -> {
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            boolean b = atomicInteger.compareAndSet(100, 101);
            if (b) {
                System.out.println("CAS验证成功");
            } else {
                System.out.println("CAS验证失败");
            }
        });

        thread1.start();
        thread2.start();

        thread1.join();
        thread2.join();

        System.out.println("处理完成");
    }

4、AtomicStampReference处理ABA问题。

private static void AtomicStampedReference通过版本戳处理ABA问题() throws InterruptedException {
        AtomicStampedReference reference = new AtomicStampedReference<Integer>(100, 1);

        Thread thread1 = new Thread(() -> {
            reference.compareAndSet(100, 101, 1, 2);
            reference.compareAndSet(101, 100, 2, 3);
        });

        Thread thread2 = new Thread(() -> {
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            boolean b = reference.compareAndSet(100, 101, 1, 2);
            if (b) {
                System.out.println("CAS验证成功");
            } else {
                System.out.println("CAS验证失败");
            }
        });

        thread1.start();
        thread2.start();

        thread1.join();
        thread2.join();

        System.out.println("处理完成");
    }
上一篇 下一篇

猜你喜欢

热点阅读