JUC之Atomic

Posted IncludeNew

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JUC之Atomic相关的知识,希望对你有一定的参考价值。

介绍

路径 : java.util.concurrent.atomic
功能 : 提供了java中的一些原子操作,包括基本类型,引用类型,数组等
内容 :

  • AtomicBoolean/AtomicInteger等基本类型的原子操作

  • AtomicIntegerArray等一些基本类型数组的原子操作

  • AtomicIntegerFieldUpdater等一些对对象成员的原子操作

  • AtomicStampedReference等为了解决CAS中的ABA问题而引入的类的原子操作,在这里可以简单的当做一个寻常类看待

Unsafe类

路径 : sun.misc.Unsafe
介绍 : Unsafe是用于在实质上扩展Java语言表达能力、便于在更高层(Java层)代码里实现原本要在更低层(C层)实现的核心库功能用的。这些功能包括裸内存的申请/释放/访问、低层硬件的atomic/volatile支持、创建未初始化对象等。它原本的设计就只应该被标准库使用,通俗的来讲,通过这个类可以绕过jvm直接对内存进行操作,以达到高效的效果,我们在使用的时候可以把Unsafe提供的接口当做一个原子操作来使用即可,此外不建议在应用中使用该类

AtomicBoolean

该类提供了基本类型的原子操作, 包括的成员方法主要为:

  1. get/set等基本的操作,java对于大多的基本类型的操作都是原子的

  2. compareAndSet类型的操作,主要是通过调用unsafe.compareAndSet实现

  3. decrementAndGet等类型操作,操作通过一种spinlock的方式来实现,该循环会一直执行,直到compareAndSet执行成功

    for (;;) {      
        int current = get();
        int next = current - 1;
        if (compareAndSet(current, next))
           return next;     }

在类中有两个比较迷惑的方法:LazySet和weakCompareAndSet

  1. LazySet可以保证原子性,但是在多线程环境下,对共享变量的修改不能保证对其他的线程立即可见

  2. weakCompareAndSet和compareAndSet的具体的实现是相同的,但是从文档中可以看到前者有两点不同:

  • 可能会出现虚假的失败,个人理解并不是说compareAndSet不会出现失败,而是对于这个函数在失败的时候可以进行重试,而前者直接抛出(没有具体验证过,如果有人知道具体的原理,欢迎批评指正)

  • 并不会提供排序的保证,就是说当一个线程看到一个通过weakCompareAndSet修改的原子变量时,它不被要求看到其他变量的修改,即便该变量的修改在weakCompareAndSet操作之前,这个跟具体的JMM模型相关

AtomicIntegerArray

AtomicIntegerFieldUpdater

AtomicMarkableReference

对一个特定的数据成员类型进行原子的操作,具体数据类型为

private static class Pair<T> {
   final T reference;
   final boolean mark;
   private Pair(T reference,
               boolean mark) {       this.reference = reference;       this.mark = mark;   }   static <T> Pair<T> of(T reference,           boolean mark) {    return new Pair<T>(reference, mark);   } }
public boolean 
compareAndSet(V expectedReference,
              V newReference,
              boolean expectedMark,
              boolean newMark) {
    Pair<V> current = pair;
    return
       expectedReference == 
            current.reference &&       expectedMark ==
            current.mark &&       ((newReference ==
            current.reference &&          newMark == current.mark) ||       casPair(current,
        Pair.of(newReference, newMark))); }

AtomicStampedReference

该类处理的数据类型与AtomicMarkableReference类似

private static class Pair<T> {
   final T reference;
   final int stamp;
   private Pair(T reference,
               int stamp) {        this.reference = reference;        this.stamp = stamp;        }   static <T> Pair<T> of(T reference,
                        int stamp) {    return new Pair<T>(reference, stamp);   } }

不同的是AtomicMarkableReference包含一个boolean类型成员,而AtomicStampedReference包含的是int类型成员,其他具体的实现方式类似, 这两个类主要用来解决CAS中ABA问题,对于一个全局变量A,初始线程1看到的是A(1)状态,后面线程2对A进行了修改转变为了A(2)状态,后面线程2又把A还原为了A(1)状态,此时CAS是无法识别A已经经过了A(1)->A(2)->A(1)的变化的,但是通过这两个类就可以解决这个问题

以上是关于JUC之Atomic的主要内容,如果未能解决你的问题,请参考以下文章

JUC并发编程 共享模式之工具 JUC CountdownLatch(倒计时锁) -- CountdownLatch应用(等待多个线程准备完毕( 可以覆盖上次的打印内)等待多个远程调用结束)(代码片段

深入理解java:2.3.1. 并发编程concurrent包 之Atomic原子操作

JUC 中的 Atomic 原子类总结

JUC多线程:Atomic原子类与CAS原理

面试必备:Java JUC Atomic LongAdder 详解

Java 语言特性——JUC(Java 并发工具包)