volatile不保证原子性

volatile不保证原子性

大厂面试题:

1、请你谈谈对volatile的理解?

2、CAS你知道吗?

3、原子类AtomicInteger的ABA问题谈谈?原子更新引用知道吗?

4、我们都知道ArrayList是线程不安全的,请编码写一个不安全的案例并给出解决方案?

5、公平锁/非公平锁/可重入锁/递归锁/自旋锁谈谈你的理解?请手写一个自旋锁。

6、CountDownLatch、CyclicBarrier、Semaphore使用过吗?

7、阻塞队列知道吗?

8、线程池用过吗?ThreadPoolExecutor谈谈你的理解?

9、线程池用过吗?生产上你是如何设置合理参数?

10、死锁编码及定位分析?

 

大厂面试题:volatile为什么不保证原子性?

大厂面试题:请你使用代码验证volatile不保证原子性?

大厂面试题:有什么办法让volatile保证原子性?

 

1、volatile不保证原子性代码验证

public class VolatileAtomDemo {

    // volatile不保证原子性

    // 原子性:保证数据一致性、完整性

    volatile int number = 0;

 

    public void addPlusPlus() {

        number++;

    }

 

    public static void main(String[] args) {

        VolatileAtomDemo volatileAtomDemo = new VolatileAtomDemo();

        for (int j = 0; j < 20; j++) {

            new Thread(() -> {

                for (int i = 0; i < 1000; i++) {

                    volatileAtomDemo.addPlusPlus();

                }

            }, String.valueOf(j)).start();

        }

 

        // 后台默认两个线程:一个是main线程,一个是gc线程

        while (Thread.activeCount() > 2) {

            Thread.yield();

        }

 

        // 如果volatile保证原子性的话,最终的结果应该是20000

        // 但是每次程序执行结果都不等于20000

        System.out.println(Thread.currentThread().getName() + "\tfinal number result = " + volatileAtomDemo.number);

    }

}

代码执行结果如下:多次执行结果证明volatile不保证原子性

 

2、volatile不保证原子性原理分析

number++操作对应的字节码:

number++被拆分成3个指令

执行GETFIELD拿到主内存中的原始值number

执行IADD进行加1操作

执行PUTFIELD把工作内存中的值写回主内存中

 

当多个线程并发执行PUTFIELD指令的时候,会出现写回主内存覆盖问题,所以才会导致最终结果不为20000,volatile不能保证原子性。

3、解决volatile不保证原子性问题

(1)方法前加synchronized解决

    public synchronized void  addPlusPlus() {

        number++;

    }

(2)加锁解决

    // 使用锁保证数据原子性

    Lock lock = new ReentrantLock();

 

    public void addPlusPlus() {

        lock.lock();

        number++;

        lock.unlock();

    }

 

(3)原子类解决

// 使用原子类保证数据原子性

public class VolatileSolveAtomDemo {

    // 原子Integer类型,保证原子性

    private AtomicInteger atomicNumber = new AtomicInteger();

 

    // 底层通过CAS保证原子性

    public void addPlusPlus() {

        atomicNumber.getAndIncrement();

    }

 

    public static void main(String[] args) {

        VolatileSolveAtomDemo volatileSolveAtomDemo = new VolatileSolveAtomDemo();

        for (int j = 0; j < 20; j++) {

            new Thread(() -> {

                for (int i = 0; i < 1000; i++) {

                    volatileSolveAtomDemo.addPlusPlus();

                }

            }, String.valueOf(j)).start();

        }

 

        // 后台默认两个线程:一个是main线程,一个是gc线程

        while (Thread.activeCount() > 2) {

            Thread.yield();

        }

 

        // 因为volatile不保证原子性,所以选择原子类AtomicInteger来解决volatile不保证原子性问题

        // 最终每次程序执行结果都等于20000

        System.out.println(Thread.currentThread().getName() + "\tfinal number result = " + volatileSolveAtomDemo.atomicNumber.get());

    }

}

代码执行结果如下:多次执行结果证明原子类是可以解决volatile不保证原子性问题

 

如果此时你已经把volatile不保证原子性原因及原理解释的很清楚,接下来面试官可能会问你:

你知道volatile禁止指令重排原理吗?

参考答案请看下一小节:volatile指令重排案例分析

 

  • 7
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值