作者:毕来生

微信: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. Dining(POJ-3281)【最大流】

    题目链接:https://vjudge.net/problem/POJ-3281 题意:厨师做了F种菜各一份,D种饮料各一份,另有N头奶牛,每只奶牛只吃特定的菜和饮料,问该厨师最多能满足多少头奶牛? ...

  2. 2020企业python真面试题持续更新中

    目录 1.软件的生命周期 2.如何知道一个python对象的类型 3.简述Django的设计模式MVC,以及你对各层的理解和用途 4.什么是lambda函数,说明其使用场景 5.python是否支持函 ...

  3. excelize

    // 参考:https://gitee.com/xurime/excelize // github.com/360EntSecGroup-Skylar/excelize

  4. spring源码(1)---idea基础环境搭建

    一.环境准备 1. jdk1.8.1 做java开发的这个应该能自己找到 2.gradle-4.9 https://services.gradle.org/distributions/ 没用过grad ...

  5. 使用zrender.js绘制体温单(1)

    之前公司请外包做了一个体温单使用的zrender.js 但是代码比较复杂维护性比较低再加上自己技术也不行 最近闲下来的时候看了一下zrender的官网慢慢的摸索并读了下之前的代码,感觉实际并不难,就自 ...

  6. Django路由及函数视图

    路由系统 在django中,uri与逻辑函数的对应关系我们称之为路由系统 伪静态 伪静态是相对于静态文件来说的,例如https://www.cnblogs.com/hesujian/p/1116581 ...

  7. Java 之 JDK9 对集合添加的优化

    通常,在代码中创建一个集合(例如,List 或 Set ),并直接用一些元素填充它. 实例化集合,几个 add方法调用,使得代码重复. Java 9,添加了几种集合工厂方法,更方便创建少量元素的集合. ...

  8. openssh升级

    转载:(感谢作者) centos7 升级openssh到openssh-8.0p1版本 https://www.cnblogs.com/nmap/p/10779658.html centos 7 op ...

  9. 数据库之sqlite

    数据创建数据 CREATE TABLE IF NOT EXISTS ArpAudit (ID INTEGER PRIMARY KEY autoincrement NOT NULL, UserName ...

  10. 栈 · 有getMin功能的栈O(1)

    题面 实现一个特殊的栈,在实现栈的基本功能的基础上,再实现返回栈中的最小元素的操作. 要求 pop(), push(), getMin()时间复杂度都是O(1) 思路 1.准备两个栈,数据栈+最小元素 ...