java不能直接訪問操作系統底層,而是通過本地方法來訪問。Unsafe類提供了硬件級別的原子操作,主要提供了以下功能:
1、通過Unsafe類可以分配內存,可以釋放內存;
類中提供的3個本地方法allocateMemory、reallocateMemory、freeMemory分別用於分配內存,擴充內存和釋放內存,與C語言中的3個方法對應。
public native long allocateMemory(long l); public native long reallocateMemory(long l, long l1); public native void freeMemory(long l);
2、可以定位對象某字段的內存位置,也可以修改對象的字段值,即使它是私有的;
字段的定位:
JAVA中對象的字段的定位可能通過staticFieldOffset方法實現,該方法返回給定field的內存地址偏移量,這個值對於給定的filed是唯一的且是固定不變的。
getIntVolatile方法獲取對象中offset偏移地址對應的整型field的值,支持volatile load語義。
getLong方法獲取對象中offset偏移地址對應的long型field的值
數組元素定位:
Unsafe類中有很多以BASE_OFFSET結尾的常量,比如ARRAY_INT_BASE_OFFSET,ARRAY_BYTE_BASE_OFFSET等,這些常量值是通過arrayBaseOffset方法得到的。arrayBaseOffset方法是一個本地方法,可以獲取數組第一個元素的偏移地址。Unsafe類中還有很多以INDEX_SCALE結尾的常量,比如 ARRAY_INT_INDEX_SCALE , ARRAY_BYTE_INDEX_SCALE等,這些常量值是通過arrayIndexScale方法得到的。arrayIndexScale方法也是一個本地方法,可以獲取數組的轉換因子,也就是數組中元素的增量地址。將arrayBaseOffset與arrayIndexScale配合使用,可以定位數組中每個元素在內存中的位置。
Arrays和Java別的對象一樣,都有一個對象頭,它是存儲在實際的數據前面的。這個頭的長度可以通過unsafe.arrayBaseOffset(T[].class)方法來獲取到,這里T是數組元素的類型。數組元素的大小可以通過unsafe.arrayIndexScale(T[].class) 方法獲取到。這也就是說要訪問類型為T的第N個元素的話,你的偏移量offset應該是arrayOffset+N*arrayScale。
public final class Unsafe { public static final int ARRAY_INT_BASE_OFFSET; public static final int ARRAY_INT_INDEX_SCALE; public native long staticFieldOffset(Field field); public native int getIntVolatile(Object obj, long l); public native long getLong(Object obj, long l); public native int arrayBaseOffset(Class class1); public native int arrayIndexScale(Class class1); static { ARRAY_INT_BASE_OFFSET = theUnsafe.arrayBaseOffset([I); ARRAY_INT_INDEX_SCALE = theUnsafe.arrayIndexScale([I); } }
3、掛起與恢復
將一個線程進行掛起是通過park方法實現的,調用 park后,線程將一直阻塞直到超時或者中斷等條件出現。unpark可以終止一個掛起的線程,使其恢復正常。整個並發框架中對線程的掛起操作被封裝在 LockSupport類中,LockSupport類中有各種版本pack方法,但最終都調用了Unsafe.park()方法。
public class LockSupport { public static void unpark(Thread thread) { if (thread != null) unsafe.unpark(thread); } public static void park(Object blocker) { Thread t = Thread.currentThread(); setBlocker(t, blocker); unsafe.park(false, 0L); setBlocker(t, null); } public static void parkNanos(Object blocker, long nanos) { if (nanos > 0) { Thread t = Thread.currentThread(); setBlocker(t, blocker); unsafe.park(false, nanos); setBlocker(t, null); } } public static void parkUntil(Object blocker, long deadline) { Thread t = Thread.currentThread(); setBlocker(t, blocker); unsafe.park(true, deadline); setBlocker(t, null); } public static void park() { unsafe.park(false, 0L); } public static void parkNanos(long nanos) { if (nanos > 0) unsafe.park(false, nanos); } public static void parkUntil(long deadline) { unsafe.park(true, deadline); } }
4、CAS操作
是通過compareAndSwapXXX方法實現的
/** * 比較obj的offset處內存位置中的值和期望的值,如果相同則更新。此更新是不可中斷的。 * * @param obj 需要更新的對象 * @param offset obj中整型field的偏移量 * @param expect 希望field中存在的值 * @param update 如果期望值expect與field的當前值相同,設置filed的值為這個新值 * @return 如果field的值被更改返回true */ public native boolean compareAndSwapInt(Object obj, long offset, int expect, int update);
CAS操作有3個操作數,內存值M,預期值E,新值U,如果M==E,則將內存值修改為B,否則啥都不做。