sun.misc.Unsafe 操作数组的例子, 参照 jdk 的 java.util.concurrent.ConcurrentHashMap的源代码
package org.fantasy.unsafe;
public interface Array<T> {
/**
* 根据下标获取指定的元素
* @param index
* @return
*/
public T getObject(int index);
/**
* 根据下标修改指定的元素
* @param index
* @param element
* @return
*/
public boolean setObject(int index, T element);
/**
* 添加元素
* @param element
* @return
*/
public boolean addObject(T element);
/**
* 删除元素
* @param element
* @return
*/
public T remove(T element);
/**
* 根据下标删除元素
* @param index
* @return
*/
public boolean remove(int index);
}
package org.fantasy.unsafe;
import java.lang.reflect.Field;
import java.util.Arrays;
import sun.misc.Unsafe;
public class ArrayUnsafe<T> implements Array<T> {
private static final int DEFAULT_INITIAL_CAPACITY = 10;
private transient volatile Object[] elements;
private volatile int size = 0;
private static final Unsafe UNSAFE;
private static final long ARRAY_OFFSET;
private static final int ARRAY_SHIFT;
private static final int INDEX_SCALE;
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
private static final long SIZE_OFFSET;
static {
try {
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
UNSAFE = (Unsafe)unsafeField.get(null);
ARRAY_OFFSET = UNSAFE.arrayBaseOffset(Object[].class);
INDEX_SCALE = UNSAFE.arrayIndexScale(Object[].class);
ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(INDEX_SCALE);
SIZE_OFFSET = UNSAFE.objectFieldOffset(ArrayUnsafe.class.getDeclaredField("size"));
} catch (Exception e) {
throw new Error(e);
}
}
public ArrayUnsafe() {
this(DEFAULT_INITIAL_CAPACITY);
}
public ArrayUnsafe(int initialCapacity) {
this.elements = new Object[initialCapacity];
}
public T getObject(int index) {
return (T)UNSAFE.getObjectVolatile(elements, getIndexScale(index));
}
public boolean setObject(int index, T element) {
rangeCheck(index);
T oldElement = getObject(index);
UNSAFE.putOrderedObject(elements, getIndexScale(index), element);
if(oldElement != null && element == null) {
int numMoved = size - index - 1;
if(numMoved > 0) {
System.arraycopy(elements, index + 1, elements, index, numMoved);
}
UNSAFE.compareAndSwapInt(this, SIZE_OFFSET, size, size - 1);
UNSAFE.putOrderedObject(elements, getIndexScale(size), null);
}
return true;
}
private long getIndexScale(long index) {
return (index << ARRAY_SHIFT) + ARRAY_OFFSET;
}
private void ensureCapacityInternal(int minCapacity) {
if(minCapacity - elements.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
int oldCapacity = elements.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if(newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if(newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elements = Arrays.copyOf(elements, newCapacity);
}
private static int hugeCapacity(int minCapacity) {
if(minCapacity < 0)
throw new OutOfMemoryError();
return minCapacity > MAX_ARRAY_SIZE ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
}
public boolean addObject(T element) {
ensureCapacityInternal(size + 1);
UNSAFE.putOrderedObject(elements, getIndexScale(size), element);
UNSAFE.compareAndSwapInt(this, SIZE_OFFSET, size, size + 1);
return true;
}
private void rangeCheck(int index) {
if(index >= size || index < 0) {
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}
}
public T remove(T element) {
for(int i = 0; i < elements.length; i++) {
int index = i;
T e = getObject(index);
if(e != null) {
if(e.equals(element)) {
setObject(index, null);
return e;
}
}
}
return null;
}
public boolean remove(int index) {
rangeCheck(index);
T removedElement = getObject(index);
if(removedElement != null)
return setObject(index, null);
return false;
}
public static void main(String[] args) {
Array<String> strArray = new ArrayUnsafe<String>();
for(int i = 0; i < 10; i++) {
strArray.addObject(String.valueOf(i));
}
strArray.addObject("hello");
strArray.addObject("world");
String s0 = strArray.getObject(0);// get "0"
String s2 = strArray.getObject(2);// get "2"
strArray.setObject(1, null);
String s6 = strArray.remove("6"); // remove "6"
String sNull = strArray.remove("foo");// null
boolean result = strArray.remove(9);
}
}