java AtomicReference 是如何工作的

How java AtomicReference works under the hood

java AtomicReference 如何在后台工作?我试着查看代码,但它是基于 sun.misc.Unsafe 所以可能另一个问题是 Unsafe 是如何工作的?

这是特定于当前实现的,可以更改,但不一定是文档

How java AtomicReference works under the hood

有两个操作。单个 read/writes 或原子交换。

  1. 单个 read/writes 是简单的 volatile 加载或存储。
  2. 原子交换需要处理器级指令。最常见的实现是在 sparc-TSO、x86 和 ia64 上发现的比较和交换 (CAS),以及在 arm、ppc 和 alpha 上发现的 LL/SC。我确信我遗漏了更多内容,但这可以让您了解范围。

another question is how Unsafe works?

Unsafe 通过利用处理器指令的本机方法工作。

来源:

http://gee.cs.oswego.edu/dl/jmm/cookbook.html

AtomicReference 有两个字段:-
* 值,即参考 * valueOffset,这是 'this' 中值的位置(以字节为单位),即 AtomicReference
在 compareAndSwap(expected, updated) 中,this-location + valueOffset 处的对象使用 == 语义与 "expected" 进行比较,如果 ==,则使用 "updated".
进行更新 这是一个单一的硬件指令,因此保证以 false return 原子地更新或失败。
从 openJDK 读取不安全的源代码。

一些重要的基本事实如下。 1> 不同线程只能竞争堆中的实例和静态成员变量space。 2> 易失性读取或写入是完全原子的,并且 serialized/happens 之前并且只能从内存中完成。这么说我的意思是任何读取都将遵循内存中的先前写入。并且任何写入都将遵循先前从内存中读取的内容。因此,任何使用 volatile 的线程都将始终看到最新的值。 AtomicReference 使用这个 属性 of volatile.

以下是AtomicReference的部分源代码。 AtomicReference 引用对象引用。该引用是 AtomicReference 实例中的一个 volatile 成员变量,如下所示。

private volatile V value;

get() 只是 returns 变量的最新值(就像 volatiles 以 "happens before" 方式所做的那样)。

public final V get()

下面是AtomicReference最重要的方法

public final boolean  compareAndSet(V expect, V update) {
        return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
}

compareAndSet(expect,update)方法调用了Java的不安全class的compareAndSwapObject()方法。这种不安全的方法调用会调用本机调用,后者会向处理器调用一条指令。 "expect" 和 "update" 各自引用一个对象。

当且仅当AtomicReference实例成员变量"value"引用同一个对象被"expect"引用时,"update"现在被赋值给这个实例变量,并且"true" 被返回。否则,返回 false。整个事情是原子完成的。没有其他线程可以在两者之间进行拦截。由于这是单处理器操作(现代计算机体系结构的魔力),因此它通常比使用同步块更快。但请记住,当需要原子更新多个变量时,AtomicReference 将无济于事。

我想添加一个完整的运行ning代码,在eclipse中可以是运行。它会清除许多混乱。这里有 22 个用户(MyTh 线程)正在尝试预订 20 个席位。以下是代码片段和完整代码。

22 个用户试图预订 20 个座位的代码片段。

for (int i = 0; i < 20; i++) {// 20 seats
            seats.add(new AtomicReference<Integer>());
        }
        Thread[] ths = new Thread[22];// 22 users
        for (int i = 0; i < ths.length; i++) {
            ths[i] = new MyTh(seats, i);
            ths[i].start();
        }

以下是完整的 运行ning 代码。

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

public class Solution {

    static List<AtomicReference<Integer>> seats;// Movie seats numbered as per
                                                // list index

    public static void main(String[] args) throws InterruptedException {
        // TODO Auto-generated method stub
        seats = new ArrayList<>();
        for (int i = 0; i < 20; i++) {// 20 seats
            seats.add(new AtomicReference<Integer>());
        }
        Thread[] ths = new Thread[22];// 22 users
        for (int i = 0; i < ths.length; i++) {
            ths[i] = new MyTh(seats, i);
            ths[i].start();
        }
        for (Thread t : ths) {
            t.join();
        }
        for (AtomicReference<Integer> seat : seats) {
            System.out.print(" " + seat.get());
        }
    }

    /**
     * id is the id of the user
     * 
     * @author sankbane
     *
     */
    static class MyTh extends Thread {// each thread is a user
        static AtomicInteger full = new AtomicInteger(0);
        List<AtomicReference<Integer>> l;//seats
        int id;//id of the users
        int seats;

        public MyTh(List<AtomicReference<Integer>> list, int userId) {
            l = list;
            this.id = userId;
            seats = list.size();
        }

        @Override
        public void run() {
            boolean reserved = false;
            try {
                while (!reserved && full.get() < seats) {
                    Thread.sleep(50);
                    int r = ThreadLocalRandom.current().nextInt(0, seats);// excludes
                                                                            // seats
                                                                            //
                    AtomicReference<Integer> el = l.get(r);
                    reserved = el.compareAndSet(null, id);// null means no user
                                                            // has reserved this
                                                            // seat
                    if (reserved)
                        full.getAndIncrement();
                }
                if (!reserved && full.get() == seats)
                    System.out.println("user " + id + " did not get a seat");
            } catch (InterruptedException ie) {
                // log it
            }
        }
    }

}