【JUC系列第二篇】-原子变量

简介: 版权声明:本文为博主原创文章,未经博主允许不得转载。如需授权请联系微信:878799579 https://blog.csdn.net/qq_878799579/article/details/85636105 作者:毕来生微信:8787995791、什么是原子变量?​ 原子变量保证了该变量的所有操作都是原子的,不会因为多线程的同时访问而导致脏数据的读取问题。
版权声明:本文为博主原创文章,未经博主允许不得转载。如需授权请联系微信:878799579 https://blog.csdn.net/qq_878799579/article/details/85636105

作者:毕来生
微信: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位处理器。请忽略以上废话。

目录
相关文章
|
2月前
|
安全 Java
多线程(进阶三:JUC)
多线程(进阶三:JUC)
44 0
|
9月前
|
Web App开发 安全 Java
JUC高并发编程(一)——JUC基础知识
JUC高并发编程(一)——JUC基础知识
101 0
|
9月前
|
SpringCloudAlibaba 安全 Java
JUC并发编程(二):线程相关知识点
实现编发编程的主要手段就是多线程。线程是操作系统里的一个概念。接下来先说说两者的定义、联系与区别。
56 0
|
10月前
|
存储 安全 算法
【Java并发编程 十一】JUC并发包下并发容器类(下)
【Java并发编程 十一】JUC并发包下并发容器类(下)
74 0
|
10月前
|
存储 安全 算法
【Java并发编程 十一】JUC并发包下并发容器类(上)
【Java并发编程 十一】JUC并发包下并发容器类(上)
52 0
|
10月前
|
安全 Java Linux
JUC (java并发编程学习分享篇)
JUC (java并发编程学习分享篇)
43 0
|
安全 Java
Java多线程进阶——JUC常见类和死锁
java中的JUC就是java.util.concurrent包下的一些标准类或者接口,这个包里的东西都是和多线程相关的,以下就是这个包中常见的类和接口的用法及示例:
120 0
Java多线程进阶——JUC常见类和死锁
|
分布式计算 并行计算 算法
92. 你说你精通Java并发,那给我讲讲JUC吧(三)
92. 你说你精通Java并发,那给我讲讲JUC吧(三)
74 0
|
安全 Java 容器
92. 你说你精通Java并发,那给我讲讲JUC吧(一)
92. 你说你精通Java并发,那给我讲讲JUC吧(一)
133 0
92. 你说你精通Java并发,那给我讲讲JUC吧(一)
|
安全 Java
92. 你说你精通Java并发,那给我讲讲JUC吧(二)
92. 你说你精通Java并发,那给我讲讲JUC吧(二)
71 1