java AtomicReference 是如何工作的
How java AtomicReference works under the hood
java AtomicReference 如何在后台工作?我试着查看代码,但它是基于 sun.misc.Unsafe 所以可能另一个问题是 Unsafe 是如何工作的?
这是特定于当前实现的,可以更改,但不一定是文档
How java AtomicReference works under the hood
有两个操作。单个 read/writes 或原子交换。
- 单个 read/writes 是简单的
volatile
加载或存储。
- 原子交换需要处理器级指令。最常见的实现是在 sparc-TSO、x86 和 ia64 上发现的比较和交换 (CAS),以及在 arm、ppc 和 alpha 上发现的 LL/SC。我确信我遗漏了更多内容,但这可以让您了解范围。
another question is how Unsafe works?
Unsafe 通过利用处理器指令的本机方法工作。
来源:
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
}
}
}
}
java AtomicReference 如何在后台工作?我试着查看代码,但它是基于 sun.misc.Unsafe 所以可能另一个问题是 Unsafe 是如何工作的?
这是特定于当前实现的,可以更改,但不一定是文档
How java AtomicReference works under the hood
有两个操作。单个 read/writes 或原子交换。
- 单个 read/writes 是简单的
volatile
加载或存储。 - 原子交换需要处理器级指令。最常见的实现是在 sparc-TSO、x86 和 ia64 上发现的比较和交换 (CAS),以及在 arm、ppc 和 alpha 上发现的 LL/SC。我确信我遗漏了更多内容,但这可以让您了解范围。
another question is how Unsafe works?
Unsafe 通过利用处理器指令的本机方法工作。
来源:
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
}
}
}
}