高并发系列之——原子操作

 jdk:1.8.0_65

1 前言

  首先需要了解什么是原子性,可以理解为CPU层面不能分割的操作,原子性只有两种状态,要么改变,要么不改变。如果多线程同时更新同一个变量,非原子操作都会出现线程安全问题,导致多线程执行后获取到的变量值与期望值不一致。

  那么如何解决线程安全问题呢,可以实现一个原子操作,有三种方式:

  第一种:使用同步技术,sychronized代码块。

  第二种:lock接口。

  第三种:原子数据结构,如AtomicBoolean、AtomicInteger、AtomicLong等。

  以下是针对原子数据结构进行解读。

2.原子数据结构

  原子数据在jdk中包路径为java.util.concurrent.atomic,原子数据结构类都是使用Unsafe实现的包装类,有11个类,可以分为四种,以下为各个类型的讲解。

2.1 原子更新基本类型

  AtomicBoolean:更新的 boolean 值。适用于多线程中状态控制,如销毁或是执行状态。

  AtomicInteger:更新的 int 值。常用于资源数量的控制操作,如线程池中资源数量,以此来判断新的任务是否加入线程池中。

  AtomicLong:更新的 long 值。

2.2 原子更新数组——更新数组中指定的值

  AtomicIntegerArray:更新其元素的 int 数组。

  AtomicLongArray:更新其元素的 long 数组。

2.3 原子更新引用类型——更新多个变量

  AtomicReference:更新的对象引用。

  AtomicMarkableReference:维护带有标记位的对象引用,可以原子方式对其进行更新。

  AtomicReferenceArray:元素的对象引用数组。

  AtomicStampedReference:维护带有整数“标志”的对象引用,可以用原子方式对其进行更新。

2.4 基于反射的实用工具类——由于此类型都是抽象类,在使用前都需要调用newUpdater创建一个updater

  AtomicIntegerFieldUpdater:可以对指定类的指定 public volatile int 字段进行原子更新。

  AtomicLongFieldUpdater:可以对指定类的指定 public volatile long 字段进行原子更新。

  AtomicReferenceFieldUpdater:可以对指定类的指定 public  volatile 字段进行原子更新。

3.原子数据结构源码分析和示例

 3.1 原子更新基本类型

 1 package Atomic;
 2 
 3 import java.util.concurrent.atomic.AtomicInteger;
 4 
 5 public class AtomicMain {
 6     //原子更新基本类型
 7     private static void atomicBaseType() {
 8         AtomicInteger atomicInteger = new AtomicInteger(10);
 9         System.out.println("先返回当前值,然后递增1:" + atomicInteger.getAndIncrement());
10         System.out.println("更新后值:" + atomicInteger.get());
11     }
12 
13     public static void main(String[] args) {
14         atomicBaseType();
15     }
16 }

运行结果:

3.2 原子更新数组

 1     //原子更新数组
 2     private static void atomicArray()
 3     {
 4         int[] atomicArray = new int[]{11,22,33};
 5         AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(atomicArray);
 6         for (int i = 0; i < atomicIntegerArray.length(); i++) {
 7             System.out.println("原值:" + atomicIntegerArray.get(i));
 8             atomicIntegerArray.incrementAndGet(i);
 9             System.out.println("新值:" + atomicIntegerArray.get(i));
10         }
11     }
12     public static void main(String[] args) {
13         atomicArray();
14     }


运行结果:

 

3.3 原子更新引用类型

 1     private static void atomicRefrence()
 2     {
 3         AtomicReference atomicReference = new AtomicReference();
 4         Person person = new Person("张三", "男", 18);
 5         atomicReference.set(person);
 6         Person person1 = new Person("张三", "女", 20);
 7 
 8         Person outPerson = (Person) atomicReference.getAndSet(person1);
 9         System.out.println("本来身份:" + outPerson.getName() + " " + outPerson.getSex() + " " + outPerson.getAge());
10         Person outPerson1 = (Person) atomicReference.get();
11         System.out.println("两年后变性身份:" + outPerson1.getName() + " " + outPerson1.getSex() + " " + outPerson1.getAge());
12     }
13     public static void main(String[] args) {
14         atomicRefrence();
15     }


运行结果:

 

3.4 基于反射的实用工具类

 1     //基于反射的实用工具类
 2     private static void atomicRefect()
 3     {
 4         AtomicIntegerFieldUpdater atomicIntegerFieldUpdater = AtomicIntegerFieldUpdater.newUpdater(PersonUpdate.class, "age");
 5         PersonUpdate person = new PersonUpdate("张三", "男", 20);
 6         int outAge = atomicIntegerFieldUpdater.getAndAdd(person, 5);
 7         System.out.println("当前信息:" + person.getName() + " " + person.getSex() + " " + outAge);
 8         int outAge1 = atomicIntegerFieldUpdater.get(person);
 9         System.out.println("五年后信息:" + person.getName() + " " + person.getSex() + " " + outAge1);
10 
11 
12     }
13     public static void main(String[] args) {
14         atomicRefect();
15     }

运行结果:

 


 

如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!

 

posted @ 2018-10-19 18:08  sun-sailing  阅读(891)  评论(0编辑  收藏  举报