Java多线程系列--“JUC原子类”03之 AtomicLongArray原子类

来源:互联网 发布:微软数据库工程师 编辑:程序博客网 时间:2024/05/18 00:40

Java多线程系列-目录
[笔记][Java7并发编程实战手册]系列目录


概要

AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray这3个数组类型的原子类的原理和用法相似。本章以AtomicLongArray对数组类型的原子类进行介绍.


AtomicLongArray介绍和函数列表

在”Java多线程系列–“JUC原子类”02之 AtomicLong原子类“中介绍过,AtomicLong是作用是对长整形进行原子操作。而AtomicLongArray的作用则是对”长整形数组”进行原子操作。

AtomicLongArray函数列表

// 创建给定长度的新 AtomicLongArray。AtomicLongArray(int length)// 创建与给定数组具有相同长度的新 AtomicLongArray,并从给定数组复制其所有元素。AtomicLongArray(long[] array)// 以原子方式将给定值添加到索引 i 的元素。long addAndGet(int i, long delta)// 如果当前值 == 预期值,则以原子方式将该值设置为给定的更新值。boolean compareAndSet(int i, long expect, long update)// 以原子方式将索引 i 的元素减1。long decrementAndGet(int i)// 获取位置 i 的当前值。long get(int i)// 以原子方式将给定值与索引 i 的元素相加。long getAndAdd(int i, long delta)// 以原子方式将索引 i 的元素减 1。long getAndDecrement(int i)// 以原子方式将索引 i 的元素加 1。long getAndIncrement(int i)// 以原子方式将位置 i 的元素设置为给定值,并返回旧值。long getAndSet(int i, long newValue)// 以原子方式将索引 i 的元素加1。long incrementAndGet(int i)// 最终将位置 i 的元素设置为给定值。void lazySet(int i, long newValue)// 返回该数组的长度。int length()// 将位置 i 的元素设置为给定值。void set(int i, long newValue)// 返回数组当前值的字符串表示形式。String toString()// 如果当前值 == 预期值,则以原子方式将该值设置为给定的更新值。boolean    weakCompareAndSet(int i, long expect, long update)

AtomicLongArray源码分析(基于JDK1.7+)

AtomicLongArray的完整源码

/* * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * * * * * * * * * * * * * * * * * * * * *//* * * * * * * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/publicdomain/zero/1.0/ */package java.util.concurrent.atomic;import sun.misc.Unsafe;import java.util.*;/** * A {@code long} array in which elements may be updated atomically. * See the {@link java.util.concurrent.atomic} package specification * for description of the properties of atomic variables. * @since 1.5 * @author Doug Lea */public class AtomicLongArray implements java.io.Serializable {    private static final long serialVersionUID = -2308431214976778248L;    private static final Unsafe unsafe = Unsafe.getUnsafe();    private static final int base = unsafe.arrayBaseOffset(long[].class);    private static final int shift;    private final long[] array;    static {        int scale = unsafe.arrayIndexScale(long[].class);        if ((scale & (scale - 1)) != 0)            throw new Error("data type scale not a power of two");        shift = 31 - Integer.numberOfLeadingZeros(scale);    }    private long checkedByteOffset(int i) {        if (i < 0 || i >= array.length)            throw new IndexOutOfBoundsException("index " + i);        return byteOffset(i);    }    private static long byteOffset(int i) {        return ((long) i << shift) + base;    }    /**     * Creates a new AtomicLongArray of the given length, with all     * elements initially zero.     *     * @param length the length of the array     */    public AtomicLongArray(int length) {        array = new long[length];    }    /**     * Creates a new AtomicLongArray with the same length as, and     * all elements copied from, the given array.     *     * @param array the array to copy elements from     * @throws NullPointerException if array is null     */    public AtomicLongArray(long[] array) {        // Visibility guaranteed by final field guarantees        this.array = array.clone();    }    /**     * Returns the length of the array.     *     * @return the length of the array     */    public final int length() {        return array.length;    }    /**     * Gets the current value at position {@code i}.     *     * @param i the index     * @return the current value     */    public final long get(int i) {        return getRaw(checkedByteOffset(i));    }    private long getRaw(long offset) {        return unsafe.getLongVolatile(array, offset);    }    /**     * Sets the element at position {@code i} to the given value.     *     * @param i the index     * @param newValue the new value     */    public final void set(int i, long newValue) {        unsafe.putLongVolatile(array, checkedByteOffset(i), newValue);    }    /**     * Eventually sets the element at position {@code i} to the given value.     *     * @param i the index     * @param newValue the new value     * @since 1.6     */    public final void lazySet(int i, long newValue) {        unsafe.putOrderedLong(array, checkedByteOffset(i), newValue);    }    /**     * Atomically sets the element at position {@code i} to the given value     * and returns the old value.     *     * @param i the index     * @param newValue the new value     * @return the previous value     */    public final long getAndSet(int i, long newValue) {        long offset = checkedByteOffset(i);        while (true) {            long current = getRaw(offset);            if (compareAndSetRaw(offset, current, newValue))                return current;        }    }    /**     * Atomically sets the element at position {@code i} to the given     * updated value if the current value {@code ==} the expected value.     *     * @param i the index     * @param expect the expected value     * @param update the new value     * @return true if successful. False return indicates that     * the actual value was not equal to the expected value.     */    public final boolean compareAndSet(int i, long expect, long update) {        return compareAndSetRaw(checkedByteOffset(i), expect, update);    }    private boolean compareAndSetRaw(long offset, long expect, long update) {        return unsafe.compareAndSwapLong(array, offset, expect, update);    }    /**     * Atomically sets the element at position {@code i} to the given     * updated value if the current value {@code ==} the expected value.     *     * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>     * and does not provide ordering guarantees, so is only rarely an     * appropriate alternative to {@code compareAndSet}.     *     * @param i the index     * @param expect the expected value     * @param update the new value     * @return true if successful.     */    public final boolean weakCompareAndSet(int i, long expect, long update) {        return compareAndSet(i, expect, update);    }    /**     * Atomically increments by one the element at index {@code i}.     *     * @param i the index     * @return the previous value     */    public final long getAndIncrement(int i) {        return getAndAdd(i, 1);    }    /**     * Atomically decrements by one the element at index {@code i}.     *     * @param i the index     * @return the previous value     */    public final long getAndDecrement(int i) {        return getAndAdd(i, -1);    }    /**     * Atomically adds the given value to the element at index {@code i}.     *     * @param i the index     * @param delta the value to add     * @return the previous value     */    public final long getAndAdd(int i, long delta) {        long offset = checkedByteOffset(i);        while (true) {            long current = getRaw(offset);            if (compareAndSetRaw(offset, current, current + delta))                return current;        }    }    /**     * Atomically increments by one the element at index {@code i}.     *     * @param i the index     * @return the updated value     */    public final long incrementAndGet(int i) {        return addAndGet(i, 1);    }    /**     * Atomically decrements by one the element at index {@code i}.     *     * @param i the index     * @return the updated value     */    public final long decrementAndGet(int i) {        return addAndGet(i, -1);    }    /**     * Atomically adds the given value to the element at index {@code i}.     *     * @param i the index     * @param delta the value to add     * @return the updated value     */    public long addAndGet(int i, long delta) {        long offset = checkedByteOffset(i);        while (true) {            long current = getRaw(offset);            long next = current + delta;            if (compareAndSetRaw(offset, current, next))                return next;        }    }    /**     * Returns the String representation of the current values of array.     * @return the String representation of the current values of array     */    public String toString() {        int iMax = array.length - 1;        if (iMax == -1)            return "[]";        StringBuilder b = new StringBuilder();        b.append('[');        for (int i = 0; ; i++) {            b.append(getRaw(byteOffset(i)));            if (i == iMax)                return b.append(']').toString();            b.append(',').append(' ');        }    }}

AtomicLongArray的代码很简单,下面仅以incrementAndGet()为例,对AtomicLong的原理进行说明。
incrementAndGet()源码如下:

public final long incrementAndGet(int i) {    return addAndGet(i, 1);}

说明:incrementAndGet()的作用是以原子方式将long数组的索引 i 的元素加1,并返回加1之后的值。

addAndGet()源码如下:

public long addAndGet(int i, long delta) {    // 检查数组是否越界    long offset = checkedByteOffset(i);    while (true) {        // 获取long型数组的索引 offset 的原始值        long current = getRaw(offset);        // 修改long型值        long next = current + delta;        // 通过CAS更新long型数组的索引 offset的值。        if (compareAndSetRaw(offset, current, next))            return next;    }}

说明:addAndGet()首先检查数组是否越界。如果没有越界的话,则先获取数组索引i的值;然后通过CAS函数更新i的值。

getRaw()源码如下

private long getRaw(long offset) {    return unsafe.getLongVolatile(array, offset);}

说明:unsafe是通过Unsafe.getUnsafe()返回的一个Unsafe对象。通过Unsafe的CAS函数对long型数组的元素进行原子操作。如compareAndSetRaw()就是调用Unsafe的CAS函数,它的源码如下:

private boolean compareAndSetRaw(long offset, long expect, long update) {    return unsafe.compareAndSwapLong(array, offset, expect, update);}

AtomicLongArray示例

public class LongArrayTest {    public static void main(String[] args) {        // 新建AtomicLongArray对象        long[] arrLong = new long[]{10, 20, 30, 40, 50};        AtomicLongArray ala = new AtomicLongArray(arrLong);        ala.set(0, 100);        for (int i = 0, len = ala.length(); i < len; i++)            System.out.printf("get(%d) : %s\n", i, ala.get(i));        System.out.printf("%20s : %s\n", "getAndDecrement(0)", ala.getAndDecrement(0));        System.out.printf("%20s : %s\n", "decrementAndGet(1)", ala.decrementAndGet(1));        System.out.printf("%20s : %s\n", "getAndIncrement(2)", ala.getAndIncrement(2));        System.out.printf("%20s : %s\n", "incrementAndGet(3)", ala.incrementAndGet(3));        System.out.printf("%20s : %s\n", "addAndGet(100)", ala.addAndGet(0, 100));        System.out.printf("%20s : %s\n", "getAndAdd(100)", ala.getAndAdd(1, 100));        System.out.printf("%20s : %s\n", "compareAndSet()", ala.compareAndSet(2, 31, 1000));        System.out.printf("%20s : %s\n", "get(2)", ala.get(2));    }}

运行结果

get(0) : 100get(1) : 20get(2) : 30get(3) : 40get(4) : 50  getAndDecrement(0) : 100  decrementAndGet(1) : 19  getAndIncrement(2) : 30  incrementAndGet(3) : 41      addAndGet(100) : 199      getAndAdd(100) : 19     compareAndSet() : true              get(2) : 1000

本文From:http://www.cnblogs.com/skywang12345/p/3514604.html

0 0
原创粉丝点击