Java AtomicReference如何在引擎盖下工作

时间:2015-07-21 18:11:33

标签: java multithreading atomic lock-free

java AtomicReference如何在引擎盖下工作?我试过查看代码,但是基于sun.misc.Unsafe,所以可能另一个问题是不安全是如何工作的?

3 个答案:

答案 0 :(得分:3)

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

  

java AtomicReference如何在幕后工作

有两个操作。单读/写或原子交换。

  1. 单个读/写是简单的volatile加载或存储。
  2. 原子交换需要处理器级指令。最常见的实现是在arm,ppc和alpha上找到的sparc-TSO,x86和ia64以及LL / SC上的Compare和Swap(CAS)。我相信还有更多我错过了但这会让你了解范围。
  3.   

    另一个问题是不安全是如何起作用的?

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

    来源:

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

答案 1 :(得分:0)

AtomicReference有两个字段: - *值,这是参考 * valueOffset,它是来自'this'的值的位置,即AtomicReference
在compareAndSwap(预期,更新)中,此位置+ valueOffset的对象使用==语义与“expected”进行比较,如果==,则使用“updated”进行更新。
这是一个单一的硬件指令,因此保证以原子方式返回或失败返回错误 从openJDK中读取不安全的源代码。

答案 2 :(得分:0)

一些重要的基本事实如下。 1>不同的线程只能竞争堆空间中的实例变量和静态成员变量。 2>易失性读或写完全是原子的且已序列化/发生过,并且只能从内存中进行。说这是我的意思是任何读取都将跟随内存中的先前写入。并且任何写操作都将遵循先前从内存中读取的内容。因此,任何使用volatile的线程都将始终看到最新的值。 AtomicReference使用volatile的此属性。

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

private volatile V value;

get()只是返回变量的最新值(就像volatile以“先发生”的方式一样)。

public final V get()

跟随是AtomicReference的最重要方法。

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

compareAndSet(expect,update)方法调用Java的不安全类的compareAndSwapObject()方法。这种不安全的方法调用会调用本地调用,该本地调用会向处理器调用一条指令。 “期望”和“更新”均引用一个对象。

仅当AtomicReference实例成员变量“值”所引用的对象相同时,才“期望”引用“更新”给该实例变量,然后返回“ true”。否则,返回false。整个过程是原子完成的。之间没有其他线程可以拦截。由于这是单处理器操作(现代计算机体系结构的魔力),因此通常比使用同步块更快。但是请记住,当需要自动更新多个变量时,AtomicReference将无济于事。

我想添加完整的运行代码,可以在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();
        }

以下是完整的运行代码。

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
            }
        }
    }

}