• (转)Java atomic原子类的使用方法和原理(一)


    在讲atomic原子类之前先看一个小例子:

    public class UseAtomic {
       
       public static void main(String[] args) {
           AtomicInteger atomicInteger=new AtomicInteger();
           for(int i=0;i<10;i++){
                Thread t=new Thread(new AtomicTest(atomicInteger));
                t.start();
                try {
                   t.join(0);
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
                   
           }
           System.out.println(atomicInteger.get());
       }
    }
    class AtomicTest implements Runnable{
       AtomicInteger atomicInteger;
       
       public AtomicTest(AtomicInteger atomicInteger){
           this.atomicInteger=atomicInteger;
       }
       @Override
       public void run() {
           atomicInteger.addAndGet(1);
           atomicInteger.addAndGet(2);
           atomicInteger.addAndGet(3);
           atomicInteger.addAndGet(4);
       }
       
    }
    

    最终的输出结果为100,可见这个程序是线程安全的。如果把AtomicInteger换成变量i的话,那最终结果就不确定了。

    打开AtomicInteger的源码可以看到:

    // setup to use Unsafe.compareAndSwapInt for updates
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    
    private volatile int value;
    

    volatile关键字用来保证内存的可见性(但不能保证线程安全性),线程读的时候直接去主内存读,写操作完成的时候立即把数据刷新到主内存当中。

    CAS简要

    /**
         * Atomically sets the value to the given updated value
         * if the current value {@code ==} the expected value.
         *
         * @param expect the expected value
         * @param update the new value
         * @return {@code true} if successful. False return indicates that
         * the actual value was not equal to the expected value.
         */
        public final boolean compareAndSet(int expect, int update) {
            return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
        }
    

    从注释就可以看出:当线程写数据的时候,先对内存中要操作的数据保留一份旧值,真正写的时候,比较当前的值是否和旧值相同,如果相同,则进行写操作。如果不同,说明在此期间值已经被修改过,则重新尝试。
    compareAndSet使用Unsafe调用native本地方法CAS(CompareAndSet)递增数值。

    CAS利用CPU调用底层指令实现。
    两种方式:总线加锁或者缓存加锁保证原子性。



    作者:zxin1
    链接:https://www.jianshu.com/p/a2f3c46d4783
    來源:简书
    简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
  • 相关阅读:
    Java 注解指导手册(下)
    CentOS安装Redis Sentinel HA集群
    EasyBCD安装CentOS双系统
    读《大型网站技术架构核心原理与案例分析》
    CentOS的Redis内存分配策略配置
    CentOS搭建VSFTP
    freemaker分页备忘
    jenkins持续集成配置备忘
    Redis常用命令
    stream转byte数组几种方式
  • 原文地址:https://www.cnblogs.com/panxuejun/p/10200585.html
Copyright © 2020-2023  润新知