Java中的原子操作类JUC-atomic

目录

一、Java中原子操作类

1.原子更新基本类型

2.原子更新数组

3.原子更新引用类型

4.原子更新字段类

二、原子操作类原理

一、Java中原子操作类

简介:

     当更新一个变量的时候,多出现数据争用的时候可能出现所意想不到的情况。这时的一般策略是使用synchronized解决,因为synchronized能够保证多个线程不会同时更新该变量。然而,从jdk 5之后,提供了粒度更细、量级更轻,并且在多核处理器具有高性能的原子操作类。因为原子操作类把竞争的范围缩小到单个变量上,这可以算是粒度最细的情况了。

     原子操作类相当于泛化的volatile变量,能够支持原子读取-修改-写操作。比如AtomicInteger表示一个int类型的数值,提供了get和set方法,这些volatile类型的变量在读取与写入上有着相同的内存语义。原子操作类共有13个类,在java.util.concurrent.atomic包下,可以分为四种类型的原子更新类:原子更新基本类型、原子更新数组类型、原子更新引用和原子更新属性

1. 原子更新基本类型

 

(使用原子方式更新基本类型,共包括3个类)

AtomicBoolean:原子更新布尔变量
AtomicInteger:原子更新整型变量
AtomicLong:原子更新长整型变量

2. 原子更新数组

 

(通过原子更新数组里的某个元素,共有3个类)

AtomicIntegerArray:原子更新整型数组的某个元素
AtomicLongArray:原子更新长整型数组的某个元素
AtomicReferenceArray:原子更新引用类型数组的某个元素

3. 原子更新引用类型

 

(需要更新引用类型往往涉及多个变量,早atomic包有三个类)

AtomicReference:原子更新引用类型
AtomicReferenceFieldUpdater:原子更新引用类型里的字段
AtomicMarkableReference:原子更新带有标记位的引用类型。

4. 原子更新字段类

 

 (如果需要原子更新某个类的某个字段,就需要用到原子更新字段类)

AtomicIntegerFieldUpdater:原子更新整型字段
AtomicLongFieldUpdater:原子更新长整型字段
AtomicStampedReference:原子更新带有版本号的引用类型

1.原子更新基本类型

       这三个都相似,以AtomicInteger为例,主要方法有:

public class AtomicInteger extends Number implements java.io.Serializable {
    //返回当前的值
    public final int get() {
        return value;
    }
    //原子更新为新值并返回旧值
    public final int getAndSet(int newValue) {
        return unsafe.getAndSetInt(this, valueOffset, newValue);
    }
    //最终会设置成新值
    public final void lazySet(int newValue) {
        unsafe.putOrderedInt(this, valueOffset, newValue);
    }
    //如果输入的值等于预期值,则以原子方式更新为新值
    public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }
    //原子自增
    public final int getAndIncrement() {
        return unsafe.getAndAddInt(this, valueOffset, 1);
    }
    //原子方式将当前值与输入值相加并返回结果
    public final int getAndAdd(int delta) {
        return unsafe.getAndAddInt(this, valueOffset, delta);
    }
}

 例子:

public class AtomicIntegerDemo {

    private static AtomicInteger atomicInteger = new AtomicInteger(0);

    public static void main(String[] args){
        for (int i = 0; i < 5; i++){
            new Thread(new Runnable() {
                public void run() {
                    //调用AtomicInteger的getAndIncement返回的是增加之前的值
                    System.out.println(atomicInteger.getAndIncrement());
                }
            }).start();
        }
        System.out.println(atomicInteger.get());
    }
}

输出结果为:
0 
1 
2 
3 
4 
5 
5

2.原子更新数组

         AtomicIntegerArray常用方法,其他类似

int addAndSet(int i, int delta):以原子方式将输入值与数组中索引为i的元素相加

boolean compareAndSet(int i, int expect, int update):如果当前值等于预期值,则以原子方式更新数组中索引为i的值为update值

例子:

public class AtomicIntegerArrayDemo {

    static int[] intResult= new int[]{1, 2};

    static AtomicIntegerArray atomicResult = new AtomicIntegerArray(value);

    public static void main(String[] args){
        atomicResult .getAndSet(0,3);
        System.out.println(atomicResult .get(0));
        System.out.println(intResult[0]);
    }
}

输出结果是:
3 
1

3.原子更新引用类型

      AtomicReference用法如下,其他类似



import java.util.concurrent.atomic.AtomicReference;


public class AtomicReferenceDemo {

    static class User{
        private String name;
        private int id;

        public User(String name, int id) {
            this.name = name;
            this.id = id;
        }

        ...setter和getter省略
    }

    public static AtomicReference<User> ar = new AtomicReference<User>();

    public static void main(String[] args){
        User user = new User("xx",11);
        ar.set(user);
        User newUser = new User("yy",22);
        ar.compareAndSet(user,newUser);
        System.out.println(ar.get().getName());
        System.out.println(ar.get().getId());
    }
}

输出结果为:
yy 
22

4.原子更新字段类

要想原子更新字段,需要两个步骤:

  1. 每次必须使用newUpdater创建一个更新器,并且需要设置想要更新的类的字段
  2. 更新类的字段(属性)必须为public volatile
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;

public class AtomicIntegerFieldUpdaterDemo {

    //创建一个原子更新器
    private static AtomicIntegerFieldUpdater<User> atomicIntegerFieldUpdater =
            AtomicIntegerFieldUpdater.newUpdater(User.class,"old");

    public static void main(String[] args){
        User user = new User("Vison",10);
        //原来的年龄
        System.out.println(atomicIntegerFieldUpdater.getAndIncrement(user));
        //现在的年龄
        System.out.println(atomicIntegerFieldUpdater.get(user));
    }

    static class User{
        private String name;
        public volatile int old;

        ...getter和setter省略
    }
}

输出结果为:
10 
11

二、原子操作类原理

       其实原子操作类都是使用CAS原理。例如

   //这里先增加,然后返回增加后的数据
    public final int addAndGet(int delta) {
        return unsafe.getAndAddInt(this, valueOffset, delta) + delta;
    }

   其他都是类似的调用unsafe类,通过JVM的原子操作来实现。

 

    原文作者:JUC
    原文地址: https://blog.csdn.net/weixin_40792878/article/details/81544738
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞