java AtomicReference如何在引擎盖下工作?我试过查看代码,但是基于sun.misc.Unsafe,所以可能另一个问题是不安全是如何工作的?
答案 0 :(得分:3)
这是特定于当前的实现,可以更改,但不一定是文档
java AtomicReference如何在幕后工作
有两个操作。单读/写或原子交换。
volatile
加载或存储。另一个问题是不安全是如何起作用的?
不安全通过利用处理器指令的本机方法工作。
来源:
答案 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
}
}
}
}