作者:毕来生

微信: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. 1、3 list 加入缓存,并postman测试

    1.pom.xml导入redis依赖 2.配置文件配置 redis 3.主类开启缓存注解 4.Service方法上加注解 @Cacheable(value="list")//val ...

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

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

  3. mysql只会使用到一个索引的原因

    select count(1) from table1 where column1 = 1 and column2 = 'foo' and column3 = 'bar' 其中column1,colu ...

  4. SrpingBoot入门到入坟01-HelloWorld和SpringBoot打Jar包

    第一个SpringBoot: 建立一个maven项目: 再pom.xml里面增加依赖: <?xml version="1.0" encoding="UTF-8&qu ...

  5. # VsCode 配置C++调试运行

    VsCode 配置C++调试运行 打开命令面板快捷键为F1,软件上写的Ctrl+Shift+P似乎没用 先安装插件使得可以运行 先自行在vsc扩展中搜索C++安装C/C++插件 再参考知乎专栏中安装c ...

  6. MySQL之创建用户和授权

    一 权限管理 我们知道我们的最高权限管理者是root用户,它拥有着最高的权限操作.包括select.update.delete.update.grant等操作.那么一般情况在公司之后DBA工程师会创建 ...

  7. zabbix硬件监控以及服务

    大家好今天给大家带来zabbix3.4.8监控主机,那么最近由于我个人的关系.没有及时的更新文章所以,很抱歉那么今天我分享的内容是zabbix3.4.8监控服务器.本章的具体监控服务器如下: 服务器的 ...

  8. JVM 内存溢出详解(栈溢出,堆溢出,持久代溢出、无法创建本地线程)

    出处:  http://www.jianshu.com/p/cd705f88cf2a 1.内存溢出和内存泄漏的区别 内存溢出 (Out Of Memory):是指程序在申请内存时,没有足够的内存空间供 ...

  9. Python开发【杂货铺】:作用域的痛点

    1.块级作用域 想想此时运行下面的程序会有输出吗?执行会成功吗? #块级作用域 if 1 == 1: name = "lzl" print(name) for i in range ...

  10. echarts的基本使用以及如何使用官方实例的方法

    <!-- 为 ECharts 准备一个具备大小(宽高)的 DOM --> <div id="box" style="width: 600px;heigh ...