栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

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

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

基本原子类

提供三个:

  • 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位系统中使用long,long是由两块32位内存共同组成的,如果对long做出修改,需要同时对这两块内存同时修改才能完成操作。

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

底层是使用Unsafe的getAndAddLong()实现的,这里是由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

构造方法:

  • 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));
    }
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/924700.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号