作者:毕来生

微信:878799579


1、什么是原子变量?

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

2、通过synchronized保证原子操作

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

3、Atomic之AtomicInteger源码分析

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

  • AtomicInteger和AtomicIntegerArray:基于Integer类型

  • AtomicBoolean:基于Boolean类型

  • AtomicLong和AtomicLongArray:基于Long类型

  • AtomicReference和AtomicReferenceArray:基于引用类型


    构造方法如下

    1. private volatile int value;
    2. /**
    3. * Creates a new AtomicInteger with the given initial value.
    4. *
    5. * @param initialValue the initial value
    6. */
    7. public AtomicInteger(int initialValue) {
    8. value = initialValue;
    9. }
    10. /**
    11. * Creates a new AtomicInteger with initial value {@code 0}.
    12. */
    13. public AtomicInteger() {
    14. }

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

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

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

4、实战演练

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

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

  1. package org.bilaisheng.juc;
  2. /**
  3. * @Author: bilaisheng
  4. * @Wechat: 878799579
  5. * @Date: 2019/1/1 21:58
  6. * @Todo: AtomicInteger 原子性错误示范。仅演示使用
  7. * @Version : JDK11 , IDEA2018
  8. */
  9. public class AtomicIntegerErrorTest {
  10. // 举例10条线程并发,实际条数请参考自己场景
  11. private static final int THREAD_COUNT = 10;
  12. private static int num = 0;
  13. public static void main(String[] args) {
  14. Thread[] threads = new Thread[THREAD_COUNT];
  15. for (int i = 0; i < THREAD_COUNT; i++) {
  16. threads[i] = new Thread(new Runnable() {
  17. @Override
  18. public void run() {
  19. // 此处设置10000.太小看不到效果。请酌情设置
  20. for (int j = 1; j <=10000 ; j++) {
  21. // 如想要看到结果请放开下行注释
  22. //System.out.println(Thread.currentThread().getName() +" num = "+num);
  23. num++ ;
  24. }
  25. }
  26. });
  27. threads[i].start();
  28. }
  29. System.out.println(Thread.currentThread().getName());
  30. System.out.println(Thread.activeCount());
  31. while (Thread.activeCount()>2){
  32. Thread.yield();
  33. }
  34. System.out.println(num);
  35. }
  36. }

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

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

  1. package org.bilaisheng.juc;
  2. import java.util.concurrent.atomic.AtomicInteger;
  3. /**
  4. * @Author: bilaisheng
  5. * @Wechat: 878799579
  6. * @Date: 2019/1/1 23:02
  7. * @Todo:
  8. * @Version : JDK11 , IDEA2018
  9. */
  10. public class AtomicIntegerTest {
  11. private static final int THREADS_CONUT = 10;
  12. public static AtomicInteger num = new AtomicInteger(0);
  13. public static void main(String[] args) {
  14. Thread[] threads = new Thread[THREADS_CONUT];
  15. for (int i = 0; i < threads.length; i++) {
  16. threads[i] = new Thread(new Runnable() {
  17. @Override
  18. public void run() {
  19. // 此处设置10000.太小看不到效果。请酌情设置
  20. for (int j = 1; j <=10000 ; j++) {
  21. // 如想要看到结果请放开下行注释
  22. //System.out.println(Thread.currentThread().getName() +" num = "+num);
  23. num.incrementAndGet();
  24. }
  25. }
  26. });
  27. threads[i].start();
  28. }
  29. while (Thread.activeCount() > 2) {
  30. Thread.yield();
  31. }
  32. System.out.println(num);
  33. }
  34. }

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

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

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

  1. private volatile long num = 4642761357212574643L;
  2. 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. Java 语言 ArrayList 和 JSONArray 相互转换

    Java 语言 ArrayList 和 JSONArray 相互转换 本篇主要讲解 ArrayList 和 fastjson 中的 JSONArray相互转换的几种常用方式,以实体类 Student. ...

  2. python并发编程之多线程(实践篇)

    一.threading模块介绍 官网链接:https://docs.python.org/3/library/threading.html?highlight=threading# 1.开启线程的两种 ...

  3. WUSTOJ 1365: 矩阵旋转(Java)

    题目链接:

  4. spring cloud微服务实践六

    本片我们就来认识下spring cloud中的zuul组件. 注:这一个系列的开发环境版本为 java1.8, spring boot2.x, spring cloud Greenwich.SR2, ...

  5. 【动态规划】洛谷2019 OI春令营 - 普及组 作业

    [P1464 Function] [题解] 按照题目意思进行递归即可,但是过程中需要用到记忆化搜索. #include<bits/stdc++.h> using namespace std ...

  6. Kubernetes 学习笔记(五):数据卷

    "数据卷"通常和"有状态"这个词同时出现,卷用于给有状态应用保存/共享状态. 常用的数据卷类型 1. emptyDir: 用于存储临时数据的空目录 emptyD ...

  7. Mac机安装RedisCluster

    版本信息 mac版本:10.14.5 redis版本:5.0.7 Step 1 : 安装redis-cli命令 安装redis-cli命令方法有N种,这里只列举一种,参考地址:<在 Mac 上搭 ...

  8. archive_lag_target参数

    需求,由于一套生产环境归档日志切换频率过低,建议修改参数,使其间隔一定时间周期自动切换生成归档日志; SQL>; THREAD# SEQUENCE# TO_CHAR(COMPLETION_TIM ...

  9. (二十二)SpringBoot之使用Druid连接池以及SQL监控和spring监控

    一.引入maven依赖 <dependencies> <dependency> <groupId>org.springframework.boot</grou ...

  10. python 切换虚拟环境

    每次电脑重启后,都要切入虚拟环境,命令总是忘记.如果使用IDE,可以指定interpeter方便的切换. 首先conda info --env  查看当前有几个环境 激活/禁用环境 source ac ...