作者:毕来生

微信:878799579


1、什么是原子变量?

​ 原子变量保证了该变量的所有操作都是原子的,不会因为多线程的同时访问而导致脏数据的读取问题。

2、通过synchronized保证原子操作

  1. 获取锁对象
  2. 获取失败/获取不到 ->阻塞队列等待
  3. 释放锁对象

3、Atomic之AtomicInteger源码分析

java.util.concurrent.atomic包下帮助我们提供了很多原子性的支持,请参考下图

  • AtomicInteger和AtomicIntegerArray:基于Integer类型

  • AtomicBoolean:基于Boolean类型

  • AtomicLong和AtomicLongArray:基于Long类型

  • AtomicReference和AtomicReferenceArray:基于引用类型


    构造方法如下

        private volatile int value;
    
        /**
    * Creates a new AtomicInteger with the given initial value.
    *
    * @param initialValue the initial value
    */
    public AtomicInteger(int initialValue) {
    value = initialValue;
    } /**
    * Creates a new AtomicInteger with initial value {@code 0}.
    */
    public AtomicInteger() {
    }

    如果通过构造方法设置原子变量。如不设置初始值则会默认初始化为0。

    以下为方法为AtomicInteger基于原子操作常用方法

    //获取当前原子变量中的值并为其设置新值
    public final int getAndSet(int newValue) //比较当前的value是否等于expect,如果是设置为update并返回true,否则返回false
    public final boolean compareAndSet(int expect, int update) //获取当前的value值并自增一
    public final int getAndIncrement() //获取当前的value值并自减一
    public final int getAndDecrement() //获取当前的value值并为value加上delta
    public final int getAndAdd(int delta)

4、实战演练

在多线程下。我希望对num = 0;进行自增,10个线程,每个线程对变量自增10000次。结果应该是100000才对。

首先我们先来一个错误示范:

package org.bilaisheng.juc;

/**
* @Author: bilaisheng
* @Wechat: 878799579
* @Date: 2019/1/1 21:58
* @Todo: AtomicInteger 原子性错误示范。仅演示使用
* @Version : JDK11 , IDEA2018
*/
public class AtomicIntegerErrorTest { // 举例10条线程并发,实际条数请参考自己场景
private static final int THREAD_COUNT = 10; private static int num = 0; public static void main(String[] args) { Thread[] threads = new Thread[THREAD_COUNT]; for (int i = 0; i < THREAD_COUNT; i++) {
threads[i] = new Thread(new Runnable() {
@Override
public void run() {
// 此处设置10000.太小看不到效果。请酌情设置
for (int j = 1; j <=10000 ; j++) {
// 如想要看到结果请放开下行注释
//System.out.println(Thread.currentThread().getName() +" num = "+num);
num++ ;
}
}
});
threads[i].start();
} System.out.println(Thread.currentThread().getName());
System.out.println(Thread.activeCount()); while (Thread.activeCount()>2){
Thread.yield();
} System.out.println(num);
} }

运行结果举例两张如下图所示。每次运行结果都不相同

接下来我们的AtomicInteger就该登场了

package org.bilaisheng.juc;

import java.util.concurrent.atomic.AtomicInteger;

/**
* @Author: bilaisheng
* @Wechat: 878799579
* @Date: 2019/1/1 23:02
* @Todo:
* @Version : JDK11 , IDEA2018
*/
public class AtomicIntegerTest { private static final int THREADS_CONUT = 10;
public static AtomicInteger num = new AtomicInteger(0); public static void main(String[] args) {
Thread[] threads = new Thread[THREADS_CONUT]; for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(new Runnable() {
@Override
public void run() {
// 此处设置10000.太小看不到效果。请酌情设置
for (int j = 1; j <=10000 ; j++) {
// 如想要看到结果请放开下行注释
//System.out.println(Thread.currentThread().getName() +" num = "+num);
num.incrementAndGet();
}
}
});
threads[i].start();
} while (Thread.activeCount() > 2) {
Thread.yield();
}
System.out.println(num);
}
}

结果是不管怎么运行结果都和预期下相同。运行结果如下图:

5、 Volatile可以保证变量原子性吗?

​ 我们先来看一下下面两行代码

private volatile long num = 4642761357212574643L;

private volatile double amt= 4642761357212574643.23165421354;

如上代码并不能保证num以及amt两个变量就是原子性的,在32位处理器中 哪怕是通过volatile关键字进行修饰也无法保证变量原子性。因为在32位系统下。如果出现了多线程同时操作某个变量。这个变量正在被线程a进行修改。此时线程b访问此变量。可能只获取到该变量的前32位,故可能会导致原子性失效。导致不可预知的情况以及错误。如果本地和生产均为64位处理器。请忽略以上废话。

【JUC系列第二篇】-原子变量的更多相关文章

  1. 深入理解javascript函数系列第二篇——函数参数

    × 目录 [1]arguments [2]内部属性 [3]函数重载[4]参数传递 前面的话 javascript函数的参数与大多数其他语言的函数的参数有所不同.函数不介意传递进来多少个参数,也不在乎传 ...

  2. 深入理解javascript作用域系列第二篇——词法作用域和动态作用域

    × 目录 [1]词法 [2]动态 前面的话 大多数时候,我们对作用域产生混乱的主要原因是分不清楚应该按照函数位置的嵌套顺序,还是按照函数的调用顺序进行变量查找.再加上this机制的干扰,使得变量查找极 ...

  3. 深入理解javascript作用域系列第二篇

    前面的话 大多数时候,我们对作用域产生混乱的主要原因是分不清楚应该按照函数位置的嵌套顺序,还是按照函数的调用顺序进行变量查找.再加上this机制的干扰,使得变量查找极易出错.这实际上是由两种作用域工作 ...

  4. 前端工程师技能之photoshop巧用系列第二篇——测量篇

    × 目录 [1]测量信息 [2]实战 [3]注意事项 前面的话 前端工程师使用photoshop进行的大量工作实际上是测量.本文是photoshop巧用系列第二篇——测量篇 测量信息 在网页制作中需要 ...

  5. [ 高并发]Java高并发编程系列第二篇--线程同步

    高并发,听起来高大上的一个词汇,在身处于互联网潮的社会大趋势下,高并发赋予了更多的传奇色彩.首先,我们可以看到很多招聘中,会提到有高并发项目者优先.高并发,意味着,你的前雇主,有很大的业务层面的需求, ...

  6. 深入理解javascript对象系列第二篇——属性操作

    × 目录 [1]查询 [2]设置 [3]删除[4]继承 前面的话 对于对象来说,属性操作是绕不开的话题.类似于“增删改查”的基本操作,属性操作分为属性查询.属性设置.属性删除,还包括属性继承.本文是对 ...

  7. 【转载】Android Metro风格的Launcher开发系列第二篇

    前言: 各位小伙伴们请原谅我隔了这么久才开始写这一系列的第二篇博客,没办法忙新产品发布,好了废话不说了,先回顾一下:在我的上一篇博客Android Metro风格的Launcher开发系列第一篇写了如 ...

  8. chromium浏览器开发系列第二篇:如何编译最新chromium源码

    说一下为什么这么晚才发第二篇,上周和这周department的工作太多了,晚上都是十点半从公司出发,回家以后实在没有多余的精力去摸键盘了.所以请大家包涵! 上期回顾: chromium源码下载: 1. ...

  9. chromium浏览器开发系列第二篇:如何编译最新chromium

    说一下为什么这么晚才发第二篇,上周和这周department的工作太多了,晚上都是十点半从公司出发,回家以后实在没有多余的精力去摸键盘了.所以请大家包涵! 上期回顾: chromium源码下载: 1. ...

随机推荐

  1. 《ucore lab1 exercise1》实验报告

    资源 ucore在线实验指导书 我的ucore实验代码 题目:理解通过make生成执行文件的过程 列出本实验各练习中对应的OS原理的知识点,并说明本实验中的实现部分如何对应和体现了原理中的基本概念和关 ...

  2. pthread_mutexattr_t设置的相关函数及其说明

    基本概述 该函数用于C函数的多线程编程中,互斥锁的初始化. 头文件:#include <pthread.h> 函数原型: int pthread_mutex_init(pthread_mu ...

  3. mui 打包发布ios 测试

    1.首先在Hbuilder新建一个app项目,把你的代码放进来 2.在manifest.json里设置你想要的一切,图标,应用名,描述,入口页面等等等,然后再配置好你程序里需要用到的模块权限,按需配置 ...

  4. mq 探究

    一 mq简介(message queue) 消息队列技术是分布式应用间交互信息的一种技术. 消息队列可驻留在内存或磁盘上,队列存储消息直到它们被应用程序读走 通过消息队列,应用程序可独立地执行-它们不 ...

  5. 控制层解析post请求中json数据的时候,有些属性值为空

    原因: 1.默认json数据解析的时候,值会赋给键的首字母是小写的封装的bean中的属性,如果没有首字母小写的属性,也不会报错.即bean中有getXXX方法时,从json到model会增加xxx属性 ...

  6. c++学习---vector

    vector存放类型不同,{}有些区别-: vector的size的返回类型: push_back的使用: 要防止缓冲区溢出,使用范围for语句:

  7. nacos搭建

    1.下载执行包 直接官网 https://nacos.io/zh-cn/docs/quick-start.html 2. 建表 3. 启动 http://10.0.0.113:8848/nacos/i ...

  8. js之split拆分字符串

    js之split拆分字符串 1.单字符拆分 let arr = str.split(',') 2.多字符拆分 let arr = str.split(/[(),]/)

  9. Iterator 其实很简单(最好理解的工厂模式的例子)

    我们都知道Iterator是一个典型的工厂模式的例子.那么我们可能会被这两个名词搞晕.首先,我们会奇怪,为什么iterator可以遍历不同类型的结合,其次,出入程序猿的我们根本不知道工厂模式是什么. ...

  10. CSS基础 布局

    1.布局的基本位置 top         距离上边的距离right       距离右边的距离bottom   距离下边的距离left         距离左边的距离 去掉布局时 html 的3mm ...