程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java多線程:“JUC原子類”03之AtomicLongArray原子類

Java多線程:“JUC原子類”03之AtomicLongArray原子類

編輯:關於JAVA

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.0_40)

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示例

 1 // LongArrayTest.java的源碼
2 import java.util.concurrent.atomic.AtomicLongArray;
3
4 public class LongArrayTest {
5 6 public static void main(String[] args){
7
8 // 新建AtomicLongArray對象
9 long[] arrLong = new long[] {10, 20, 30, 40, 50};
10 AtomicLongArray ala = new AtomicLongArray(arrLong);
11
12 ala.set(0, 100);
13 for (int i=0, len=ala.length(); i<len; i++)
14 System.out.printf("get(%d) : %s\n", i, ala.get(i));
15
16 System.out.printf("%20s : %s\n", "getAndDecrement(0)", ala.getAndDecrement(0));
17 System.out.printf("%20s : %s\n", "decrementAndGet(1)", ala.decrementAndGet(1));
18 System.out.printf("%20s : %s\n", "getAndIncrement(2)", ala.getAndIncrement(2));
19 System.out.printf("%20s : %s\n", "incrementAndGet(3)", ala.incrementAndGet(3));
20
21 System.out.printf("%20s : %s\n", "addAndGet(100)", ala.addAndGet(0, 100));
22 System.out.printf("%20s : %s\n", "getAndAdd(100)", ala.getAndAdd(1, 100));
23
24 System.out.printf("%20s : %s\n", "compareAndSet()", ala.compareAndSet(2, 31, 1000));
25 System.out.printf("%20s : %s\n", "get(2)", ala.get(2));
26 }
27 }

運行結果:

get(0) : 100
get(1) : 20
get(2) : 30
get(3) : 40
get(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

查看本欄目

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved