Java高并发之无锁与Atomic源码分析(4)

// 获得数组第i个下标的元素
public final int get(int i)
// 获得数组的长度
public final int length()
// 将数组第i个下标设置为newValue,并返回旧的值
public final int getAndSet(int i, int newValue)
// 进行CAS操作,如果第i个下标的元素等于expect,则设置为update,设置成功返回true
public final boolean compareAndSet(int i, int expect, int update)
// 将第i个下标的元素加1
public final int getAndIncrement(int i)
// 将第i个下标的元素减1
public final int getAndDecrement(int i)
// 将第i个下标的元素增加delta(delta可以是负数)
public final int getAndAdd(int i, int delta)

源码分析

// 数组本身基地址
    private static final int base = unsafe.arrayBaseOffset(int[].class);

// 封装了一个数组
    private final int[] array;

static {
        // 数组中对象的宽度, int类型, 4个字节, scale = 4;
        int scale = unsafe.arrayIndexScale(int[].class);
        if ((scale & (scale - 1)) != 0)
            throw new Error("data type scale not a power of two");
        // 前导0 : 一个数字转为二进制后, 他前面0的个数
        // 对于4来讲, 他就是00000000 00000000 00000000 00000100, 他的前导0 就是29
        // 所以shift = 2
        shift = 31 - Integer.numberOfLeadingZeros(scale);
    }

// 获取第i个元素
    public final int get(int i) {
        return getRaw(checkedByteOffset(i));
    }

// 第i个元素, 在数组中的偏移量是多少
    private long checkedByteOffset(int i) {
        if (i < 0 || i >= array.length)
            throw new IndexOutOfBoundsException("index " + i);

return byteOffset(i);
    }

// base : 数组基地址, i << shift, 其实就是i * 4, 因为这边是int array.
    private static long byteOffset(int i) {
        // i * 4 + base
        return ((long) i << shift) + base;
    }

// 根据偏移量从数组中获取数据
    private int getRaw(long offset) {
        return unsafe.getIntVolatile(array, offset);
    }

Demo

import java.util.concurrent.atomic.AtomicIntegerArray;

public class AtomicArrayDemo {
    static AtomicIntegerArray arr = new AtomicIntegerArray(10);

public static class AddThread implements Runnable {
        public void run() {
            for (int k = 0; k < 10000; k++) {
                arr.incrementAndGet(k % arr.length());
            }
        }
    }

public static void main(String[] args) throws InterruptedException {
        Thread[] ts = new Thread[10];
        for (int k = 0; k < 10; k++) {
            ts[k] = new Thread(new AddThread());
        }
        for (int k = 0; k < 10; k++) {
            ts[k].start();
        }
        for (int k = 0; k < 10; k++) {
            ts[k].join();
        }
        System.out.println(arr);
    }
}

AtomicIntegerFieldUpdater

让普通变量也享受原子操作

主要接口

1 AtomicIntegerFieldUpdater.newUpdater()
2 incrementAndGet()

Updater只能修改它可见范围内的变量。因为Updater使用反射得到这个变量。如果变量不可见,就会出错。比如如果score申明为private,就是不可行的。

为了确保变量被正确的读取,它必须是volatile类型的。如果我们原有代码中未申明这个类型,那么简单得申明一下就行,这不会引起什么问题。

由于CAS操作会通过对象实例中的偏移量直接进行赋值,因此,它不支持static字段(Unsafe.objectFieldOffset()不支持静态变量)。

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/51b69d57160bd926d840d2e47e93aab2.html