Java中Unsafe類詳解

java不能直接訪問操做系統底層,而是經過本地方法來訪問。Unsafe類提供了硬件級別的原子操做,主要提供瞭如下功能:java

一、經過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);

二、能夠定位對象某字段的內存位置,也能夠修改對象的字段值,即便它是私有的;框架

字段的定位:操作系統

JAVA中對象的字段的定位可能經過staticFieldOffset方法實現,該方法返回給定field的內存地址偏移量,這個值對於給定的filed是惟一的且是固定不變的。線程

getIntVolatile方法獲取對象中offset偏移地址對應的整型field的值,支持volatile load語義。對象

getLong方法獲取對象中offset偏移地址對應的long型field的值內存

數組元素定位:get

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配合使用,能夠定位數組中每一個元素在內存中的位置。class

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);
    }
}

三、掛起與恢復

將一個線程進行掛起是經過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);
    }
}

 

四、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,不然啥都不作。

相關文章
相關標籤/搜索