首先要了解一下Java中的原子性的含义

  • Java中的原子性就是指操作不可再分,在多线程操作中,具有原子性的量,同一时刻只能有一个线程来对它进行操作。

  • 例如a=1是原子性操作,a++和a+=1不是原子性操作

  • 类似"a += b"这样的操作不具有原子性,在某些JVM中"a += b"可能要经过这样三个步骤:

      (1)取出a和b(2)计算a+b(3)将计算结果写入内存
    

Java中的Atomic包

Java从JDK1.5开始提供了java.util.concurrent.atomic包,方便程序员在多线程环境下,无锁的进行原子操作。原子变量的底层使用了处理器提供的原子指令,但是不同的CPU架构可能提供的原子指令不一样,也有可能需要某种形式的内部锁,所以该方法不能绝对保证线程不被阻塞。

Atomic包

  • 在Atomic包里一共有12个类,四种原子更新方式,分别是原子更新基本类型,原子更新数组,原子更新引用和原子更新字段。Atomic包里的类基本都是使用Unsafe实现的包装类。

为什么使用AtomicInteger

我们知道java并发机制中主要有三个特性需要我们去考虑,原子性、可见性和有序性。synchronized关键字可以保证可见性和有序性却无法保证原子性。而这个AtomicInteger的作用就是为了保证原子性。

AtomicInteger的常用方法如下:

int addAndGet(int delta)
//以原子方式将输入的数值与实例中的值(AtomicInteger里的value)相加,并返回新值int getAndAdd(int delta)
//以原子方式将输入的数值与实例中的值(AtomicInteger里的value)相加,并返回旧值int getAndSet(int newValue)
//以原子方式设置为newValue的值,并返回旧值。int getAndIncrement()
//以原子方式将当前值加1,注意:这里返回的旧值。int getAndDecrement()
//以原子方式将当前值减1,注意:这里返回的旧值。getCurrentValue() //获取当前值setValue() //设置ValueincrementAndGet() //先加1,然后获取新值decrementAndGet() //先减1,然后获取新值

源码:

我们看看incrementAndGet方法的源码,发现使用的是unsafe的getAndAddInt方法,还有一个valueOffset的参数

    /*** Atomically increments by one the current value.** @return the updated value*/public final int incrementAndGet() {return unsafe.getAndAddInt(this, valueOffset, 1) + 1;}

我们可以发现在开头出现了unsafe,上面有一行注释Unsafe.compareAndSwapInt

public class AtomicInteger extends Number implements java.io.Serializable {private static final long serialVersionUID = 6214790243416807050L;// setup to use Unsafe.compareAndSwapInt for updatesprivate static final Unsafe unsafe = Unsafe.getUnsafe();private static final long valueOffset;static {try {valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));} catch (Exception ex) { throw new Error(ex); }}
  • compareAndSwap的含义
    compareAndSwap又叫做CAS,CAS 即比较并替换,实现并发算法时常用到的一种技术。算法是为了保证数据的原子性。CAS操作包含三个操作数——内存位置、预期原值及新值。执行CAS操作的时候,将内存位置的值与预期原值比较,如果相匹配,那么处理器会自动将该位置值更新为新值,否则,处理器不做任何操作。
    内存值 V
    预估值 A
    更新值 B
    当且仅当 V== A 时,V = B , 否则,将不做任何操作。
  • Unsafe的含义
    • Unsafe是位于sun.misc包下的一个类,Unsafe类使Java语言拥有了类似C语言指针一样操作内存空间的能力,这无疑也增加了程序发生相关指针问题的风险。在程序中过度、不正确使用Unsafe类会使得程序出错的概率变大,使得Java这种安全的语言变得不再“安全”,因此对Unsafe的使用一定要慎重。
    • 在jdk1.9中,对Usafe进行了删除,所以因为这,那些基于Usafe开发的框架慢慢的都死掉了。Usafe在进行getAndAddInt的时候,首先是先加1,然后对底层对象的地址做出了更改。
  • valueOffset的含义
    • 这个valueOffset是long类型的,代表的含义就是对象的地址的偏移量。unsafe.getAndAddInt(this, valueOffset, 1) + 1。这行代码的含义是,usafe通过getAndAddInt方法,对原先对象的地址进行了加1操作。

在使用CAS实现原子操作可能带来ABA问题.
我们知道CAS的原理是在比较操作值的时候,检查值有没有发生变化,如果没有发生变化则更新,但是如果一个值原来是A,中间变成B,最后又变成A,那么使用CAS进行检查时会发现值没有发生变化,但是实际上是变化了的。

解决方法:时间戳、版本号
JDK1.5之后,Atomic包提供的类AtomicStampedReference就解决了这个问题。这个类的compareAndSet方法先检查当前引用是否等于预期引用,并且检查当前标志是否等于预期标志,如果全部相等,则以原子方式将该引用和该标志的值设置为给定的更新值。

CAS算法模拟public class TestCompareAndSwap {public static void main(String[] args) {final CompareAndSwap cas = new CompareAndSwap();for (int i = 0; i < 10; i++) {new Thread(new Runnable() {@Overridepublic void run() {    //先get一次内存中的值int expectedValue = cas.get();boolean b = cas.compareAndSet(expectedValue, (int)(Math.random() * 101));System.out.println(b);}}).start();}}
}
class CompareAndSwap{private int value;//获取内存值public synchronized int get() {return value;}//比较public synchronized int compareAndSwap(int expectedValue, int newValue) {//在这里第二次获取内存中的值int oldValue = value;if(oldValue == expectedValue) {this.value = newValue;}return oldValue;}public synchronized boolean compareAndSet(int expectedValue, int newValue) {return expectedValue == compareAndSwap(expectedValue, newValue);}
}

AtomicInteger类下的incrementAndGet相关推荐

  1. AtomicInteger类的理解与使用

    前言 JDK1.5之后的java.util.concurrent.atomic包里,多了一批原子处理类.AtomicBoolean.AtomicInteger.AtomicLong.AtomicRef ...

  2. [ 转载 ] Java基础10--关于Object类下所有方法的简单解析

    关于Object类下所有方法的简单解析 类Object是类层次结构的根类,是每一个类的父类,所有的对象包括数组,String,Integer等包装类,所以了解Object是很有必要的,话不多说,我们直 ...

  3. python语言下同一个类下有多个函数,其中一个函数想调用另外一个函数里面的变量怎么调用

    一:问题,同一个类下,有多个函数,其中一个函数想调用另外一个函数里面的变量怎么调用 解决方法:在调用函数里面,初始化一下被调用的函数,然后就可以直接使用被调用函数数里面的变量了 self.被调用函数名 ...

  4. 获取System.Drawing.SystemColors类下的所有颜色

    System.Drawing.SystemColors下的颜色主要用在windows下的窗口.菜单.文本.按钮等等使用的颜色.现在想把这些颜色使 用到web上,如果直接使用名称的话,可能有些浏览器无法 ...

  5. selenium - Select类 - 下拉框

    WebDriver提供了Select类来处理下拉框. 如百度搜索设置的下拉框,如下图: from selenium import webdriver from selenium.webdriver.s ...

  6. 如何在Java Reflection中的类下获取所有方法信息?

    本文以我以前的文章为基础 . 在本文中,我们将看到如何使用Java Reflection检索类相关信息. 我们将重点介绍方法名称. 注意:我将创建一个单独的反射器实用程序类,在该类中,我们在其构造函数 ...

  7. ssh备考-05Struts2 Action类下的重要API(原生Servlet的API、跳转配置、框架自身的数据封装、自定义拦截器)

    目录 一.Struts框架中如何使用原生Servlet的API 方法一.使用ActionContext类(完全解耦合的方式)(不好用,了解) demo1.jsp demo1Action.java    ...

  8. 计算机专业大类下,还有哪些细分的专业,分别是干什么的?

    作者:罗文 链接:https://www.zhihu.com/question/40819195/answer/129677777 来源:知乎 著作权归作者所有,转载请联系作者获得授权. 之前就有想过 ...

  9. jq循环取同一个类下的标签值

    部分前台代码:<div class="form_comm_box add_msg"><img src="__STYLE__/images/safe_na ...

最新文章

  1. DSP学习 -- C语言实现MySQL数据库操作
  2. json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
  3. Hibernate所用15个jar包
  4. android之appwidget(一)简单appwidget
  5. 【华为云实战开发】13.如何在云端快速搭建python网站
  6. oracle 数据管理,Oracle深入浅出之数据管理
  7. JAVA爬虫Nutch、WebCollector的正则约束
  8. IDEA之配置SVN
  9. 自动化专业好找工作吗?就业方向是什么?
  10. 产品管理:四步法新产品开发流程
  11. HTML5基本标签使用header,nav和footer
  12. 创建物理卷报错Can‘t open /dev/sdb1 exclusively. Mounted filesystem?以及对应的解决方法
  13. pdf 转换为图片格式(可提高兼容性)
  14. 优动漫PAINT入门小知识——拾色器功能
  15. Java入门第三季—简易扑克牌游戏
  16. TCP: too many of orphaned sockets报错解决
  17. requests使用socks代理
  18. linux ps -elf 查看进程获取进程id
  19. SQL Server数据库作业:连接查询
  20. python:感知型对象和简单型对象

热门文章

  1. 单总线CPU微程序控制器设计
  2. 【03】Linux笔记
  3. vertica MySQL_Vertica数据库 安装 | 学步园
  4. 【21天习惯养成记~~day17晚】
  5. 分页插件中关于PageInfo
  6. 深度学习图像标签标注软件labelme超详细教程
  7. 快速申请开通公众号门店小程序-微信小程序开发-视频教程7
  8. ES6 新特性之 let, const : JavaScript在变量方面的改进。
  9. 南邮 OJ 1128 An Industrial Spy
  10. Java如何判断字符串中包含有全角,半角符号