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


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

  • 相关阅读:
    Windows下编译TensorFlow1.3 C++ library及创建一个简单的TensorFlow C++程序
    flask自动重启与配置文件导入,路由重定向(8)
    go(4)字符串的应用
    go(3)变量的应用与数据类型
    go(2)输出,转义,字符接收
    go(1)
    tornado集成wtforms
    HTML5笔记007
    HTML5笔记006
    HTML5笔记005
  • 原文地址:https://www.cnblogs.com/bilaisheng/p/10210895.html
Copyright © 2020-2023  润新知