1)解决并发不是用锁就能解决吗,那SDK干嘛还要搞个原子类出来?

  • 锁虽然能解决,但是加锁解锁始终还是对性能是有影响的,并且使用不当可能会造成死锁之类的问题。

2)原子类是怎样使用的,比如说我要实现一个线程安全的累加器?

 public class Test {
   AtomicLong count =
     new AtomicLong(0); // 原子类变量count
   void add10K() {
     int idx = 0;
     while(idx++ < 10000) {
       count.getAndIncrement();// 原子操作
    }
  }
 }

3)原子类是无锁的,那他底层是靠什么来实现原子安全的?

  • 靠硬件。我们的CPU为了解决并发问题,提供了CAS指令,而CPU的指令本身就是原子性的。

4)什么是CAS呢?

  • compare and swap ,他主要就看3个参数,A是共享变量的内存地址,B是用于和原地址值比较的,C是我们要更新的值。

  • 其实就是把原来的共享变量的值取出一份来,然后你要更新的话,得对比一下,当前的值和我取出来保存的这份值是不是相同的,如果是相同的,那就可以修改,不同的话说明被别人修改过了,那你现在就不能更新。

     ​
     class SimulatedCAS{
       int count;
       synchronized int cas(
         int expect, int newValue){
         // 读目前count的值
         int curValue = count;
         // 比较目前count值是否==期望值
         if(curValue == expect){
           // 如果是,则更新count的值
           count = newValue;
        }
         // 返回写入前的值
         return curValue;
      }
     }

5)假如我当前的值和我取出来的那份值不一样了,那该怎么办?

  • CAS一般带有自旋,所谓自旋也就是循环的意思。当值不同了 ,那就从头来进行:取值来放着--->对比--->相同的话那就更新,不同就从头再来。

     ​
     class SimulatedCAS{
       volatile int count;
       // 实现count+=1
       addOne(){
         do {
           newValue = count+1; //①
        }while(count !=
           cas(count,newValue) //②
      }
       // 模拟实现CAS,仅用来帮助理解
       synchronized int cas(
         int expect, int newValue){
         // 读目前count的值
         int curValue = count;
         // 比较目前count值是否==期望值
         if(curValue == expect){
           // 如果是,则更新count的值
           count= newValue;
        }
         // 返回写入前的值
         return curValue;
      }
     }
  • 从上面代码我们也可以看出来,完全是没有加锁解锁的操作的,所以CAS这种无锁实现并发的操作性能很好。

6)我们说凡事都有两面性,CAS他就没任何的缺点吗?

  • 会存在ABA问题,比如之前我取出来了一份值是A,但是在我进行对比之前,其它线程悄悄滴过来 ,把我的共享变量修改为了B,然后又修改成了A。虽然看到的都是A,其实这是被修改过的了。

7)两个数值反正都是相同的,不影响我的更新,那我还在乎ABA干嘛?

  • 如果我们只是进行数值的原子递增之类的操作,那我们是不需要关心的。但是如果是对象呢,对象就比数值讲究多了,可能 A表面都是 一样的,但是属性是不一样的。

8)怎样解决ABA问题呢?

  • 在使用 CAS 方案的时候,一定要先 check 一下。

9)前面我们使用原子类 AtomicLong 的 getAndIncrement() 方法替代了count += 1,从而实现了线程安全。原子类 AtomicLong 的 getAndIncrement() 方法内部就是基于 CAS 实现的,那 Java 是如何使用 CAS 来实现原子化的count += 1的?

  • Java 1.8 版本中,getAndIncrement() 方法会转调 unsafe.getAndAddLong() 方法。这里 this 和 valueOffset 两个参数可以唯一确定共享变量的内存地址。

     final long getAndIncrement() {
       return unsafe.getAndAddLong(
         this, valueOffset, 1L);
     }

10)unsafe.getAndAddLong() 方法的底层源码实现是怎样的?

  • 该方法首先会在内存中读取共享变量的值

  • 之后循环调用 compareAndSwapLong() 方法来尝试设置共享变量的值,直到成功为止。

  • compareAndSwapLong() 是一个 native 方法,只有当内存中共享变量的值等于 expected 时,才会将共享变量的值更新为 x,并且返回 true;否则返回 fasle。

     ​
     public final long getAndAddLong(
       Object o, long offset, long delta){
       long v;
       do {
         // 读取内存中的值
         v = getLongVolatile(o, offset);
      } while (!compareAndSwapLong(
           o, offset, v, v + delta));
       return v;
     }
     //原子性地将变量更新为x
     //条件是内存中的值等于expected
     //更新成功则返回true
     native boolean compareAndSwapLong(
       Object o, long offset,
       long expected,
       long x);

11)SDK中提供了哪些原子类给我们使用?

使用提示:Java 提供的原子类能够解决一些简单的原子性问题,但是我们所有原子类的方法都是针对一个共享变量的,如果你需要解决多个变量的原子性问题,建议还是使用互斥锁方案。原子类虽好,但使用要非常小心。

java的原子类到底是啥?ABA,CAS又是些什么?的更多相关文章

  1. java 线程 原子类相关操作演示样例 thinking in java4 文件夹21.3.4

    java 线程  原子类相关操作演示样例 package org.rui.thread.volatiles; import java.util.Timer; import java.util.Time ...

  2. Java并发—原子类,java.util.concurrent.atomic包(转载)

    原子类 Java从JDK 1.5开始提供了java.util.concurrent.atomic包(以下简称Atomic包),这个包中 的原子操作类提供了一种用法简单.性能高效.线程安全地更新一个变量 ...

  3. java并发:原子类之AtomicLong

    原子类之AtomicLong java线程中的操作,需要满足原子性.可见性等原则,比如i++这样的操作不具备原子性, A线程读取了i,另一个线程执行i++,A线程再执行i++就会引发线程安全问题 推荐 ...

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

    在讲atomic原子类之前先看一个小例子: public class UseAtomic { public static void main(String[] args) { AtomicIntege ...

  5. java的原子类 AtomicInteger 实现原理是什么?

    采用硬件提供原子操作指令实现的,即CAS.每次调用都会先判断预期的值是否符合,才进行写操作,保证数据安全. CAS机制 CAS是英文单词Compare And Swap的缩写,翻译过来就是比较并替换. ...

  6. Java - “JUC”原子类

    根据修改的数据类型,可以将JUC包中的原子操作类可以分为4类. 1. 基本类型: AtomicInteger, AtomicLong, AtomicBoolean ;2. 数组类型: AtomicIn ...

  7. CAS 算法与 Java 原子类

    乐观锁 一般而言,在并发情况下我们必须通过一定的手段来保证数据的准确性,如果没有做好并发控制,就可能导致脏读.幻读和不可重复度等一系列问题.乐观锁是人们为了应付并发问题而提出的一种思想,具体的实现则有 ...

  8. Java多线程系列——原子类的实现(CAS算法)

    1.什么是CAS? CAS:Compare and Swap,即比较再交换. jdk5增加了并发包java.util.concurrent.*,其下面的类使用CAS算法实现了区别于synchronou ...

  9. java并发编程(十三)----(JUC原子类)引用类型介绍(CAS和ABA的介绍)

    这一节我们将探讨引用类型原子类:AtomicReference, AtomicStampedRerence, AtomicMarkableReference.AtomicReference的使用非常简 ...

随机推荐

  1. MySQL中使用IN会不会走索引

    结论:IN肯定会走索引,但是当IN的取值范围较大时会导致索引失效,走全表扫描 navicat可视化工具使用explain函数查看sql执行信息 场景1:当IN中的取值只有一个主键时 我们只需要注意一个 ...

  2. windows下后台启动PHP,Nginx,Redis(使用RunHiddenConsole)

    启动命令(红色代码可选): 启动PHP RunHiddenConsole D:/phpStudy/PHPTutorial/php/php-5.6.27-nts/php-cgi.exe -b 127.0 ...

  3. HBase海量数据高效入仓解决方案

    一.方案背景 现阶段部分业务数据存储在HBase中,这部分数据体量较大,达到数十亿.大数据需要增量同步这部分业务数据到数据仓库中,进行离线分析,目前主要的同步方式是通过HBase的hive映射表来实现 ...

  4. hadoop-SSH免密登录配置

    一:配置基础环境 一.修改主机名 修改 master 机器主机名 [root@server ~]# hostnamectl set-hostname master-wzg [root@server ~ ...

  5. Spring Boot 进行优雅的字段校验

    Controller层 VS Service层 一般推荐与业务无关的放在Controller层中进行校验,而与业务有关的放在Service层中进行校验. 那么如何将参数校验写的优雅美观呢,如果都是if ...

  6. Vtune工具简介

    VTune是 Intel 提供的一个强大的应用程序性能分析软件,VTune Amplifier XE 2011 集成了Intel VTune Performance Analyzer 和 Thread ...

  7. 【模板】动态 DP

    luogu传送门. 最近学了一下动态dp,感觉没有想象的难. 动态DP simple的DP是这样的: 给棵树,每个点给个权值,求一下最大权独立集. 动态DP是这样的: 给棵树,每个点给个权值还到处改, ...

  8. SpringBoot:自定义注解实现后台接收Json参数

    0.需求 在实际的开发过程中,服务间调用一般使用Json传参的模式,SpringBoot项目无法使用@RequestParam接收Json传参 只有@RequestBody支持Json,但是每次为了一 ...

  9. JAVA 用命令提示符执行java找不到或者无法加载主类

    使用cmd编译执行java文件时候,报错---找不到或者无法加载主类如下图 把红色部分去掉,再次编译执行如下解决问题 ,执行成功!!!!!! 2.当我们在eclipes中执行运行的时候 ggggggg ...

  10. java常见字节大小存储问题

    JAVA中默认的编码方式 转:http://blog.csdn.net/scyatcs/article/details/31356823 编码问题存在两个方面:JVM之内和JVM之外.1.Java文件 ...