zoukankan      html  css  js  c++  java
  • java并发包 Atomic

    CAS机制

      除了synchronized之外,java还提供了一些并发包。比如现在这段代码,肯定会有并发问题,我们当然可以通过重磅的 synchronized 锁来解决多线程并发问题,但是这样就有点杀鸡用牛刀了。我们可以用Atomic原子类来解决这个问题。

    import java.util.concurrent.atomic.AtomicInteger;
    public class Demo {
        // 初始值0
        private static int num = 0;
        public static void inCreate(){
            //自增
            num++;
        }
    //    Atomic 解决并发问题
    //    // 初始值0
    //    private static AtomicInteger num = new AtomicInteger(0);
    //    public synchronized static void inCreate(){
    //        // 自增
    //        num.incrementAndGet();
    //    }
    
        public static void main(String[] args) throws InterruptedException {
            for (int i = 0; i < 10; i++) {
                new Thread(() -> {
                    for (int j = 0; j < 100; j++) {
                        inCreate();
                        try {
                            Thread.sleep(10);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }).start();
            }
            Thread.sleep(2000);// 等待两秒,让上面10个线程先执行完
            System.out.println(num);// 结果为1000才是对的
        }
    }

      Atomic 原子类不是传统意义的锁机制,它是无锁化的 CAS 机制,通过 CAS 机制保证多线程修改个数值的安全性,CAS的全称是:Compare and Set,也就是先较再设置的意思。

      

    Atomic源码

      我们在操作 atomic 的时候,实际上就是对 value 的修改,它是被 volatile 修饰的,也就是说变更之后马上就可以被其他线程感知到。

      我们调用 incrementAndGet 自增方法,就是通过 Unsafe 类来做的,它负责执行 CAS操作。它是jdk内部的一个类,我们在自己的系统中使用 Unsafe.getUnsafe() 是会报错的,因为类加载器是不同的。

    先分析下参数,看看它整个的调用过程:
      var1:就是我们传入的this,就是 AtomicInteger 这个类对象。
      var2:就是 valueOffest,也就是我们的value的偏移量。
      var4:增加的值,1。
      var5:内存中旧的值。
      首先通过 this.getIntVolatile(var1, var2); 根据 AtomicInteger 的value偏移量,获取到了内存中旧的值 var5 ,就是我们当时设置的0。
      然后通过 while 无限循环去执行 this.compareAndSwapInt(AtomicInteger, valueOffest, 0, 0 + 1)。这个过程就是 CAS 操作,它是被 native 修饰的,底层就是 C 发送的 cpu 指令,通过一个线程对某块小内存中的数据进行修改。
      最后就把旧的值 var5 返回来了,然后 return 0+1,我们就看到了新的值 1。

    CAS优化

      刚才我们模拟CAS执行过程知道,要是获取到的值和内存不一致,那么它会一直无线循环;如果是大量线程同时涌入,必然会导致大量线程空循环,性能和效率都不是特别好。所以java8使用LongAdder使用分段的方式进行了优化。在longadder中,一开始所有线程都是对base进行操作。如果线程较多,就会实行分段CAS机制,也就是内部会搞一个cell数组,每个数组是一个数值分段,让每一个cell去处理一些请求;如果某一个cell执行cas失败了,则会自动去找另一个cell进行cas操作;最后将所有cell分段数值加起来返回给你。

        // LongAdder 解决并发问题
        // 初始值0
        private static LongAdder num = new LongAdder();
        public synchronized static void inCreate(){
            // 自增
            num.add(1);
        }

      

  • 相关阅读:
    Flutter Android ERROR: ensureInitializationComplete must be called after startInitialization
    MySQL 创建用户表和好友表
    Android 广播的使用 文档使用的是 kotlin版本
    Flutter 分段器的使用
    Flutter 计算两个日期之间相差多少天,生成区间随机数
    Flutter 多环境
    Android ListView 的使用 Kotlin
    Android 自定义控件----基础
    Flutter 学习(3)------------通过List或者map循环数据渲染页面。。
    vs2015 编译报错:The project references NuGet package(s) that are missing on this computer...
  • 原文地址:https://www.cnblogs.com/wlwl/p/15004462.html
Copyright © 2011-2022 走看看