How java AtomicReference works under the hood
This is specific to the current implementation and may change, but not necessarily docs
How java AtomicReference works under the hood
There are two operations. Single read / write or atomic swaps.
- Single reads / writes are easy to
volatile
load or save. - Atomic swaps require processor-level instructions. The most common implementations are Compare and Swap (CAS) found on sparc-TSO, x86 and ia64, and LL / SC found on hand, ppc and alpha. I'm sure I'm no more, but that gives you an idea of ββthe volume.
Another question: how does Unsafe work?
Runs unsafely through native methods using processor instructions.
Sources:
source to share
AtomicReference has two fields: -
* value, which is a reference * offset value, which is the position of the value in bytes from 'this', that is, AtomicReference In compareAndSwap (expected, updated), the object at that location + the Offset value is compared using == semantics with " expected ", and if ==, it is updated with" updated ".
This is a separate hardware instruction and is thus guaranteed to update or false-return crash atomically.
Read the unsafe source code from openJDK.
source to share
Some important elementary facts are as follows. 1> Different threads can only fight for instance and static member variables in heap space. 2> Volatile reads or writes are completely atomic and serialize / happen earlier and are done only from memory. By this I mean that any read will follow the previous write in memory. And any record will follow the previous read from memory. This way, any thread working with volatile will always see the most current value. AtomicReference uses this volatile property.
Following are some source codes for AtomicReference. AtomicReference refers to an object reference. This reference is a volatile variable in the AtomicReference instance as shown below.
private volatile V value;
get () simply returns the last value of the variable (as it does in the volatile "happens first" way).
public final V get()
Following is the most important AtomicReference method.
public final boolean compareAndSet(V expect, V update) {
return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
}
The compareAndSet (await, update) method calls the compareAndSwapObject () method of an unsafe Java class. This call to the unsafe method invokes its own call, which invokes a single instruction for the processor. "expect" and "update" every object reference.
If and only if the AtomicReference instance member variable "value" refers to the same object, it is referenced by "pending", this instance variable is now assigned "update" and returns true. Or else, the lie comes back. All this is done atomically. No other thread can intercept in between. Since this is a uniprocessor operation (the magic of modern computer architecture), it is often faster than using a synchronized block. But remember that when multiple variables need to be updated atomically, AtomicReference won't help.
I would like to add a complete working code that can be run in Eclipse. It would be clear a lot of confusion. There are 22 users (MyTh themes) trying to book 20 seats. Below is the code snippet followed by the complete code.
A snippet of code in which 22 users are trying to book 20 seats.
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();
}
Below is the complete working code.
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
}
}
}
}
source to share