How java AtomicReference works under the hood

How does java AtomicReference work under the hood? I tried looking at the code but is based on sun.misc.Unsafe, so maybe another question: how does Unsafe work?

+3


source to share


3 answers


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:

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

+4


source


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.



0


source


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

}    

      

0


source







All Articles