【juc学习之路第4天】基本原子类与数组原子类

6 篇文章 0 订阅

基本原子类

提供三个:

  • AtomicInteger: public class AtomicInteger extends Number implements java.io.Serializable
  • AtomicLong: public class AtomicLong extends Number implements java.io.Serializable
  • AtomicBoolean: public class AtomicBoolean implements java.io.Serializable

使用方法

public class Main {
    public static void main(String[] args) throws InterruptedException {
        AtomicLong num = new AtomicLong(0);
        for (int i = 0; i < 3; i ++) {
            new Thread(() -> {
                System.out.printf("[%s]number: %d \n",
                        Thread.currentThread().getName(), num.addAndGet(100));
            }).start();
        }
        TimeUnit.SECONDS.sleep(1);
        System.out.println("get answer: " + num);
    }
}

[Thread-0]number: 200
[Thread-1]number: 100
[Thread-2]number: 300
get answer: 300

AtomicLong与AtomicInteger的区别

AtomicLong中,比AtomicInteger多了一部分内容:

static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8();
private static native boolean VMSupportsCS8();

long是64位的,如果在32位系统中使用longlong是由两块32位内存共同组成的,如果对long做出修改,需要同时对这两块内存同时修改才能完成操作。

addAndGet()

public final long addAndGet(long delta) {
  	return U.getAndAddLong(this, VALUE, delta) + delta;
}

底层是使用UnsafegetAndAddLong()实现的,这里是由CPU实现的,而不再是Java实现的。好处在于执行速度快,而且避免了数据在内存之中的互相拷贝带来的额外开销。

@HotSpotIntrinsicCandidate
public final long getAndAddLong(Object o, long offset, long delta) {
    long v;
    do {
      	v = getLongVolatile(o, offset);
    } while (!weakCompareAndSetLong(o, offset, v, v + delta));
    return v;
}
@HotSpotIntrinsicCandidate
public native long getLongVolatile(Object o, long offset);
@HotSpotIntrinsicCandidate
public final boolean weakCompareAndSetLong(Object o, long offset, long expected, long x) {
		return compareAndSetLong(o, offset, expected, x);
}
@HotSpotIntrinsicCandidate
public final native boolean compareAndSetLong(Object o, long offset,long expected,long x);

comareAndSet()

对数据内容进行修改,修改之前会判断当前值是否与期望值excepted相同,如果相同则修改为x,否则不允许修改。这是一种乐观锁实现机制。

在这里插入图片描述
在这里插入图片描述

compareAndset()数据修改操作方法在JUC中被称为CAS机制,CAS(Compare-And-Swap)是一条CPU并发原语(是CPU的原生指令,是直接写在CPU内部的程序代码)。它的功能是判断内存某个位置的值是否为预期值,如果是则更改为新的值,反之则不进行修改,这个过程属于原子性操作。

在多线程进行数据修改时,为了保证数据修改的正确性,常规的做法就是使用synchronized同步锁,但是这种锁属于悲
观锁(Pessimistic Lock),每一个线程都需要在操作之前锁定当前的内存区域,而后才可以进行处理,这样一来在高并发环境下就会严重影响到程序的处理性能。

而CAS采用的是乐观锁(Optimistic Lock)机制,其最大的操作特点是不进行强制性的同步处理(没有 synchronized),而为了保证数据修改的正确性,添加了一些比较的数据(例如:compareAndset()在修改之前需要进行数据的比较),采用的是一种冲突重试的处理机制,这样可以有效的避免线程阻塞问题的出现。在并发竞争不是很激烈的情况下,可以获得较好的处理性能。而在JDK 9后为了进一步提升CAS的操作性能,又追加了硬件处理指令集的支持,可以充分的发挥服务器硬件配置的优势,得到更好的处理性能。

  • JDK 9+:@HotSpotIntrinsicCandidate
  • JDK17:@IntrinsicCandidate

数组原子类

提供三个:

  • AtomicIntegerArray
  • AtomicLongArray
  • AtomicReferenceArray<E>

构造方法:

  • public AtomicIntegerArray(int length):初始化数组长度
  • public AtomicIntegerArray(int[] array):根据已有数组初始化(深拷贝)

源码:

public class AtomicIntegerArray implements java.io.Serializable {
    private static final long serialVersionUID = 2862133569453604235L;
    private static final VarHandle AA
        = MethodHandles.arrayElementVarHandle(int[].class);
    private final int[] array;

compareAndSet()

public final boolean compareAndSet(int i, int expectedValue, int newValue) {
		return AA.compareAndSet(array, i, expectedValue, newValue);
}

在原子数组操作类中的CAS机制,在JDK1.7之后不是由Unsafe提供的,而是由java.lang.invoke中的VarHandle提供的。该类主要用于动态操作数组元素或对象的成员属性。VarHandle类提供了一系列的标准内存屏障操作,用于更细粒度的控制指令排序,在安全性、可用性以及性能方面都要优于已有的程序类库,同时可以和任何类型的变量进行关联操作。

VarHandle

此类是在java.lang.invoke包下的,顾名思义VarHandle应该也是一个反射操作类。为什么会有它的出现呢?我们知道,过多的反射机制造成了Java执行困难的问题(JVM导致的),但在VarHandle里提供了更佳的反射操作。

  • JDK1.7-11:
public abstract class VarHandle {
    final VarForm vform;

    VarHandle(VarForm vform) {
        this.vform = vform;
    }
  • JDK12+:

Constable常量描述类

public abstract class VarHandle implements Constable {
    final VarForm vform;
    final boolean exact;

    VarHandle(VarForm vform) {
        this(vform, false);
    }

    VarHandle(VarForm vform, boolean exact) {
        this.vform = vform;
        this.exact = exact;
    }

使用VarHandle实现反射

public class Main {
    public static void main(String[] args) throws Exception {
        VarHandle varHandle = MethodHandles.lookup()
          	.findVarHandle(Person.class, "name", String.class);
        Person person = Person.class.getDeclaredConstructor().newInstance();
        varHandle.set(person, "birdy");
        System.out.println(varHandle.get(person));
    }
}
MethodHandles
public class MethodHandles {

    private MethodHandles() { }  // do not instantiate
    public static VarHandle arrayElementVarHandle(Class<?> arrayClass) throws Exception {
        return VarHandles.makeArrayElementHandle(arrayClass);
    }
}

模拟AtomicIntegerArray实现CAS操作

public class Main {
    public static void main(String[] args) throws InterruptedException {
        int[] array = new int[] {1,2,3};
        VarHandle varHandle = MethodHandles.arrayElementVarHandle(int[].class);
        varHandle.compareAndSet(array, 2, 3, 5);
        System.out.println(Arrays.toString(array));
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

edanhuang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值