i++是安全的吗?AtomicInteger解决这个安全问题。

  • Post author:
  • Post category:其他




i++问题

i++和++i在这个问题上是一样的。

一个简单的 i++ 操作,看似简单,但是它的底层是由三条 CPU 指令完成的,但正是 i++ 是没有原子性确定的,在底层运行当中就可能会有 CPU 的调度产生,造成 i 的值被修改,造成脏读脏写。

volatile 是不能解决这个问题的,因为 i++ 不安全是因为原子性的问题,volition 只能保证线程的可见性和有序性。

在解决这个问题的时候,可以使用 synchronized 或者 ReentrantLock 都是可以解决这个问题的,在这一般使用的是 synchronized 更好,因为 JVM 在版本更新迭代的时候就一直在优化改进这个机制,是可以尽早的获得更好的性能,并且synchronized 对大多数开发人员来说更加熟悉,方便代码的阅读。


戳这里:了解synchronized和ReentrantLock 解决原子性问题

也可以使用 AtomicInteger 来解决这个问题。AtomicInteger 类的底层实现原理利用处理器的 CAS 操作(Compare And Swap,比较与交换,一种无锁的算法)

戳这里:具体了解CAS是什么

用 CAS 来检测栈中的值是否被其他线程所改变,如果被改变则 CAS 操作失败。这种实现方法在CPU指令级别实现了原子操作。

因此,使用 CAS 是比 synchronized 来实现同步效率更高的。



AtomicInteger

AtomicInteger 是 Integer 类提供的原子操作。常见的原子操作类还有 AtomicBoolean、AtomicLong、AtomicReference等,它们的实现原理是相同的,区别就在于运算的对象的类型不同。

还可以通过 AtomicReference< V > 将一个对象的所有操作都转换为原子操作。

AtomicInteger 的性能通常是 synchronized 和 ReentrantLock 的好几倍。

而 AtomicInteger 的具体用法:

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.atomic.AtomicInteger;

public class AtomicIntegerDemo {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        AtomicIntegerTest test = new AtomicIntegerTest();
        FutureTask<AtomicInteger> task = new FutureTask<>(test);
        Thread thread1 = new Thread(task);
        Thread thread2 = new Thread(task);
        thread1.start();
        thread2.start();
        System.out.println(task.get());//获得线程里面最后返回的值
    }
}

class AtomicIntegerTest implements Callable<AtomicInteger> {
    //定义一个原子操作
    AtomicInteger num = new AtomicInteger(0);

    @Override
    public AtomicInteger call() {
        for (int i = 0; i < 1000000; i++) {
            num.getAndIncrement();   //通过原子操作数执行自增操作
        }
        return num;
    }
}

在这里插入图片描述



版权声明:本文为weixin_45970271原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。