1. 程式人生 > >Unsafe--Java中Unsafe類詳解

Unsafe--Java中Unsafe類詳解

java不能直接訪問作業系統底層,而是通過本地方法來訪問。Unsafe類提供了硬體級別的原子操作,主要提供了以下功能:

1、通過Unsafe類可以分配記憶體,可以釋放記憶體;

類中提供的3個本地方法allocateMemory、reallocateMemory、freeMemory分別用於分配記憶體,擴充記憶體和釋放記憶體,與C語言中的3個方法對應。

2、可以定位物件某欄位的記憶體位置,也可以修改物件的欄位值,即使它是私有的;
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的值

陣列元素定位:

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配合使用,可以定位陣列中每個元素在記憶體中的位置。

複製程式碼
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,否則啥都不做。

參考資料:

首先介紹一下什麼是Compare And Swap(CAS)?簡單的說就是比較並交換。

CAS 操作包含三個運算元 —— 記憶體位置(V)、預期原值(A)和新值(B)。如果記憶體位置的值與預期原值相匹配,那麼處理器會自動將該位置值更新為新值。否則,處理器不做任何操作。無論哪種情況,它都會在 CAS 指令之前返回該位置的值。CAS 有效地說明了“我認為位置 V 應該包含值 A;如果包含該值,則將 B 放到這個位置;否則,不要更改該位置,只告訴我這個位置現在的值即可。” Java併發包(java.util.concurrent)中大量使用了CAS操作,涉及到併發的地方都呼叫了sun.misc.Unsafe類方法進行CAS操作。

在看一下volatile, Volatile修飾的成員變數在每次被執行緒訪問時,都強迫從共享記憶體中重讀該成員變數的值。而且,當成員變數發生變化時,強迫執行緒將變化值回寫到共享記憶體。這樣在任何時刻,兩個不同的執行緒總是看到某個成員變數的值是相同的,更簡單一點理解就是volatile修飾的變數值發生變化時對於另外的執行緒是可見的。

如何正確使用volatile可以參考下面這篇文章:

下面來看看java中具體的CAS操作類sun.misc.Unsafe。Unsafe類提供了硬體級別的原子操作,Java無法直接訪問到作業系統底層(如系統硬體等),為此Java使用native方法來擴充套件Java程式的功能。具體實現使用c++,詳見檔案sun.misc.natUnsafe.cc();sun.misc包的原始碼可以在這裡找到:

複製程式碼
//下面是sun.misc.Unsafe.java類原始碼
package sun.misc;
import java.lang.reflect.Field;
/***
 * This class should provide access to low-level operations and its
 * use should be limited to trusted code.  Fields can be accessed using
 * memory addresses, with undefined behaviour occurring if invalid memory
 * addresses are given.
 * 這個類提供了一個更底層的操作並且應該在受信任的程式碼中使用。可以通過記憶體地址
 * 存取fields,如果給出的記憶體地址是無效的那麼會有一個不確定的執行表現。
 * 
 * @author Tom Tromey ([email protected])
 * @author Andrew John Hughes ([email protected])
 */
public class Unsafe
{
  // Singleton class.
  private static Unsafe unsafe = new Unsafe();
  /***
   * Private default constructor to prevent creation of an arbitrary
   * number of instances.
   * 使用私有預設構造器防止建立多個例項
   */
  private Unsafe()
  {
  }
  /***
   * Retrieve the singleton instance of <code>Unsafe</code>.  The calling
   * method should guard this instance from untrusted code, as it provides
   * access to low-level operations such as direct memory access.
   * 獲取<code>Unsafe</code>的單例,這個方法呼叫應該防止在不可信的程式碼中例項,
   * 因為unsafe類提供了一個低級別的操作,例如直接記憶體存取。
   * 
   * @throws SecurityException if a security manager exists and prevents
   *                           access to the system properties.
   *                           如果安全管理器不存在或者禁止訪問系統屬性
   */
  public static Unsafe getUnsafe()
  {
    SecurityManager sm = System.getSecurityManager();
    if (sm != null)
      sm.checkPropertiesAccess();
    return unsafe;
  }
  
  /***
   * Returns the memory address offset of the given static field.
   * The offset is merely used as a means to access a particular field
   * in the other methods of this class.  The value is unique to the given
   * field and the same value should be returned on each subsequent call.
   * 返回指定靜態field的記憶體地址偏移量,在這個類的其他方法中這個值只是被用作一個訪問
   * 特定field的一個方式。這個值對於 給定的field是唯一的,並且後續對該方法的呼叫都應該
   * 返回相同的值。
   *
   * @param field the field whose offset should be returned.
   *              需要返回偏移量的field
   * @return the offset of the given field.
   *         指定field的偏移量
   */
  public native long objectFieldOffset(Field field);
  /***
   * Compares the value of the integer field at the specified offset
   * in the supplied object with the given expected value, and updates
   * it if they match.  The operation of this method should be atomic,
   * thus providing an uninterruptible way of updating an integer field.
   * 在obj的offset位置比較integer field和期望的值,如果相同則更新。這個方法
   * 的操作應該是原子的,因此提供了一種不可中斷的方式更新integer field。
   * 
   * @param obj the object containing the field to modify.
   *            包含要修改field的物件
   * @param offset the offset of the integer field within <code>obj</code>.
   *               <code>obj</code>中整型field的偏移量
   * @param expect the expected value of the field.
   *               希望field中存在的值
   * @param update the new value of the field if it equals <code>expect</code>.
   *           如果期望值expect與field的當前值相同,設定filed的值為這個新值
   * @return true if the field was changed.
   *                             如果field的值被更改
   */
  public native boolean compareAndSwapInt(Object obj, long offset,
                                          int expect, int update);
  /***
   * Compares the value of the long field at the specified offset
   * in the supplied object with the given expected value, and updates
   * it if they match.  The operation of this method should be atomic,
   * thus providing an uninterruptible way of updating a long field.
   * 在obj的offset位置比較long field和期望的值,如果相同則更新。這個方法
   * 的操作應該是原子的,因此提供了一種不可中斷的方式更新long field。
   * 
   * @param obj the object containing the field to modify.
   *              包含要修改field的物件 
   * @param offset the offset of the long field within <code>obj</code>.
   *               <code>obj</code>中long型field的偏移量
   * @param expect the expected value of the field.
   *               希望field中存在的值
   * @param update the new value of the field if it equals <code>expect</code>.
   *               如果期望值expect與field的當前值相同,設定filed的值為這個新值
   * @return true if the field was changed.
   *              如果field的值被更改
   */
  public native boolean compareAndSwapLong(Object obj, long offset,
                                           long expect, long update);
  /***
   * Compares the value of the object field at the specified offset
   * in the supplied object with the given expected value, and updates
   * it if they match.  The operation of this method should be atomic,
   * thus providing an uninterruptible way of updating an object field.
   * 在obj的offset位置比較object field和期望的值,如果相同則更新。這個方法
   * 的操作應該是原子的,因此提供了一種不可中斷的方式更新object field。
   * 
   * @param obj the object containing the field to modify.
   *    包含要修改field的物件 
   * @param offset the offset of the object field within <code>obj</code>.
   *         <code>obj</code>中object型field的偏移量
   * @param expect the expected value of the field.
   *               希望field中存在的值
   * @param update the new value of the field if it equals <code>expect</code>.
   *               如果期望值expect與field的當前值相同,設定filed的值為這個新值
   * @return true if the field was changed.
   *              如果field的值被更改
   */
  public native boolean compareAndSwapObject(Object obj, long offset,
                                             Object expect, Object update);
  /***
   * Sets the value of the integer field at the specified offset in the
   * supplied object to the given value.  This is an ordered or lazy
   * version of <code>putIntVolatile(Object,long,int)</code>, which
   * doesn't guarantee the immediate visibility of the change to other
   * threads.  It is only really useful where the integer field is
   * <code>volatile</code>, and is thus expected to change unexpectedly.
   * 設定obj物件中offset偏移地址對應的整型field的值為指定值。這是一個有序或者
   * 有延遲的<code>putIntVolatile</cdoe>方法,並且不保證值的改變被其他執行緒立
   * 即看到。只有在field被<code>volatile</code>修飾並且期望被意外修改的時候
   * 使用才有用。
   * 
   * @param obj the object containing the field to modify.
   *    包含需要修改field的物件
   * @param offset the offset of the integer field within <code>obj</code>.
   *       <code>obj</code>中整型field的偏移量
   * @param value the new value of the field.
   *      field將被設定的新值
   * @see #putIntVolatile(Object,long,int)
   */
  public native void putOrderedInt(Object obj, long offset, int value);
  /***
   * Sets the value of the long field at the specified offset in the
   * supplied object to the given value.  This is an ordered or lazy
   * version of <code>putLongVolatile(Object,long,long)</code>, which
   * doesn't guarantee the immediate visibility of the change to other
   * threads.  It is only really useful where the long field is
   * <code>volatile</code>, and is thus expected to change unexpectedly.
   * 設定obj物件中offset偏移地址對應的long型field的值為指定值。這是一個有序或者
   * 有延遲的<code>putLongVolatile</cdoe>方法,並且不保證值的改變被其他執行緒立
   * 即看到。只有在field被<code>volatile</code>修飾並且期望被意外修改的時候
   * 使用才有用。
   * 
   * @param obj the object containing the field to modify.
   *    包含需要修改field的物件
   * @param offset the offset of the long field within <code>obj</code>.
   *       <code>obj</code>中long型field的偏移量
   * @param value the new value of the field.
   *      field將被設定的新值
   * @see #putLongVolatile(Object,long,long)
   */
  public native void putOrderedLong(Object obj, long offset, long value);
  /***
   * Sets the value of the object field at the specified offset in the
   * supplied object to the given value.  This is an ordered or lazy
   * version of <code>putObjectVolatile(Object,long,Object)</code>, which
   * doesn't guarantee the immediate visibility of the change to other
   * threads.  It is only really useful where the object field is
   * <code>volatile</code>, and is thus expected to change unexpectedly.
   * 設定obj物件中offset偏移地址對應的object型field的值為指定值。這是一個有序或者
   * 有延遲的<code>putObjectVolatile</cdoe>方法,並且不保證值的改變被其他執行緒立
   * 即看到。只有在field被<code>volatile</code>修飾並且期望被意外修改的時候
   * 使用才有用。
   *
   * @param obj the object containing the field to modify.
   *    包含需要修改field的物件
   * @param offset the offset of the object field within <code>obj</code>.
   *       <code>obj</code>中long型field的偏移量
   * @param value the new value of the field.
   *      field將被設定的新值
   */
  public native void putOrderedObject(Object obj, long offset, Object value);
  /***
   * Sets the value of the integer field at the specified offset in the
   * supplied object to the given value, with volatile store semantics.
   * 設定obj物件中offset偏移地址對應的整型field的值為指定值。支援volatile store語義
   * 
   * @param obj the object containing the field to modify.
   *    包含需要修改field的物件
   * @param offset the offset of the integer field within <code>obj</code>.
   *       <code>obj</code>中整型field的偏移量
   * @param value the new value of the field.
   *       field將被設定的新值
   */
  public native void putIntVolatile(Object obj, long offset, int value);
  /***
   * Retrieves the value of the integer field at the specified offset in the
   * supplied object with volatile load semantics.
   * 獲取obj物件中offset偏移地址對應的整型field的值,支援volatile load語義。
   * 
   * @param obj the object containing the field to read.
   *    包含需要去讀取的field的物件
   * @param offset the offset of the integer field within <code>obj</code>.
   *       <code>obj</code>中整型field的偏移量
   */
  public native int getIntVolatile(Object obj, long offset);
  /***
   * Sets the value of the long field at the specified offset in the
   * supplied object to the given value, with volatile store semantics.
   * 設定obj物件中offset偏移地址對應的long型field的值為指定值。支援volatile store語義
   *
   * @param obj the object containing the field to modify.
   *            包含需要修改field的物件
   * @param offset the offset of the long field within <code>obj</code>.
   *               <code>obj</code>中long型field的偏移量
   * @param value the new value of the field.
   *              field將被設定的新值
   * @see #putLong(Object,long,long)
   */
  public native void putLongVolatile(Object obj, long offset, long value);
  /***
   * Sets the value of the long field at the specified offset in the
   * supplied object to the given value.
   * 設定obj物件中offset偏移地址對應的long型field的值為指定值。
   * 
   * @param obj the object containing the field to modify.
   *     包含需要修改field的物件
   * @param offset the offset of the long field within <code>obj</code>.
   *     <code>obj</code>中long型field的偏移量
   * @param value the new value of the field.
   *     field將被設定的新值
   * @see #putLongVolatile(Object,long,long)
   */
  public native void putLong(Object obj, long offset, long value);
  /***
   * Retrieves the value of the long field at the specified offset in the
   * supplied object with volatile load semantics.
   * 獲取obj物件中offset偏移地址對應的long型field的值,支援volatile load語義。
   * 
   * @param obj the object containing the field to read.
   *    包含需要去讀取的field的物件
   * @param offset the offset of the long field within <code>obj</code>.
   *       <code>obj</code>中long型field的偏移量
   * @see #getLong(Object,long)
   */
  public native long getLongVolatile(Object obj, long offset);
  /***
   * Retrieves the value of the long field at the specified offset in the
   * supplied object.
   * 獲取obj物件中offset偏移地址對應的long型field的值
   * 
   * @param obj the object containing the field to read.
   *    包含需要去讀取的field的物件
   * @param offset the offset of the long field within <code>obj</code>.
   *       <code>obj</code>中long型field的偏移量
   * @see #getLongVolatile(Object,long)
   */
  public native long getLong(Object obj, long offset);
  /***
   * Sets the value of the object field at the specified offset in the
   * supplied object to the given value, with volatile store semantics.
   * 設定obj物件中offset偏移地址對應的object型field的值為指定值。支援volatile store語義
   * 
   * @param obj the object containing the field to modify.
   *    包含需要修改field的物件
   * @param offset the offset of the object field within <code>obj</code>.
   *     <code>obj</code>中object型field的偏移量
   * @param value the new value of the field.
   *       field將被設定的新值
   * @see #putObject(Object,long,Object)
   */
  public native void putObjectVolatile(Object obj, long offset, Object value);
  /***
   * Sets the value of the object field at the specified offset in the
   * supplied object to the given value.
   * 設定obj物件中offset偏移地址對應的object型field的值為指定值。
   * 
   * @param obj the object containing the field to modify.
   *    包含需要修改field的物件
   * @param offset the offset of the object field within <code>obj</code>.
   *     <code>obj</code>中object型field的偏移量
   * @param value the new value of the field.
   *       field將被設定的新值
   * @see
            
           

相關推薦

javaString

String類 String類存在java.lang包中,專門儲存字串。是引用資料型別。 String類的兩種例項化方法 1.直接賦值 String str1= "hello"; 2.傳統賦值 Str

JavaClass、用法以及泛化

在前面我們將類的載入的時候,類載入一共有5步,載入,驗證,準備,解析和初始化。其中載入階段,除了將位元組碼載入到方法區,還生成了這個了的Java.lang.Class物件。那麼這個Class物件到底有什麼用呢? 前面的關於反射的文章,我們多次都用到了Class類,可以用這個

Javadimension

dimension - Java的一個類         dimension是Java的一個類,封裝了一個構件的高度和寬度,這個類與一個構件的許多屬性具有相關性,因此在Component類中定義多個與之有關的方法,LayoutManager介面也與一個Dimension

JavaNumber

1.資料型別基本簡介 一般情況下我們會使用資料的基本資料型別:byte、int、short、long、double、float、boolean、char; 對應的包裝型別也有八種:Byte、Integ

JavaArrayList

1、什麼是ArrayList  ArrayList就是傳說中的動態陣列,用MSDN中的說法,就是Array的複雜版本,它提供瞭如下一些好處:  動態的增加和減少元素  實現了ICollection和IList介面  靈活的設定陣列的大小 2、如何使用ArrayList

Unsafe--JavaUnsafe

java不能直接訪問作業系統底層,而是通過本地方法來訪問。Unsafe類提供了硬體級別的原子操作,主要提供了以下功能: 1、通過Unsafe類可以分配記憶體,可以釋放記憶體; 類中提供的3個本地方法allocateMemory、reallocateMemory、freeMemory分別用於分配記憶體,

javaClass物件名.class, class.forName(), getClass()區別

package yerasel; import java.lang.reflect.Method; public class Test { /** * @param args */ public static void main(String[] args) {

java Io 流

修改 文件目錄 != exe [] 深入 clas one fileinput 關於java 流類的復習;習慣性的復習按照圖結構一層層往下深入去了解去復習,最後通過代碼來實現感覺印象會更深刻一些; 關於 I/O流:IO可以理解為JAVA用來傳遞數據的管道

Java反射機制

turn face instance java struct () 分享 2.6 一個     序言       在學習java基礎時,由於學的不紮實,講的實用性不強,就覺得沒用,很多重要的知識就那樣一筆帶過了,像這個馬上要講的反射機制一樣,當時學的時候就忽略了,到後來學習

Java的ant

問題 noi mar gin otf left 源代碼 都是 tps 分享一套幾十個源代碼,都是vc++的,打包提供 包含指針的結構數組,初始化問題 《!———— C++ 中 export 關鍵字的尷尬處境 ————》 想做一個小東西不知從何入手 493YR誒詰B駝

Java 的resultset

ins 浮點 relative 字符串類型 更新 for 變量 占用 nec 結果集(ResultSet)是數據中查詢結果返回的一種對象,可以說結果集是一個存儲查詢結果的對象,但是結果集並不僅僅具有存儲的功能,他同時還具有操縱數據的功能,可能完成對數據的更新等。   結果集

Javajar命令

 做專案的時候我們肯定接觸過很多jar包,那麼jar包是什麼呢?筆者瞭解到jar是java archive file 的簡寫。從名字就可以知道,它的應用與Java息息相關。下面就詳細介紹如何自己生成jar包,這樣我們管理我們自己的程式碼(尤其是一些比較重要而且不會或者很少有修改的程式碼)。  安裝好J

Java併發工具

在JDK的併發包裡提供了幾個非常有用的併發工具類。CountDownLatch、CyclicBarrier和Semaphore工具類提供了一種併發流程控制的手段,Exchanger工具類則提供了線上程間交換資料的一種手段。本章會配合一些應用場景來介紹如何使用這些工具類。 等待多執行緒完成的Cou

JavaSimpleDateFormat用法

轉自:http://blog.csdn.net/linbooooo1987/article/details/7540999 [java]  view plain  copy

Java物件頭

一:物件頭 HotSpot虛擬機器中,物件在記憶體中儲存的佈局可以分為三塊區域:物件頭(Header)、例項資料(Instance Data)和對齊填充(Padding)。   HotSpot虛擬機器的物件頭(Object Header)包括兩部分資訊,第一部分用於儲存物

JavaDate型別

一、Date型別的初始化 1、 Date(int year, int month, int date); 直接寫入年份是得不到正確的結果的。 因為java中Date是從1900年開始算的,所以前面的第一個引數只要填入從1900年後過了多少年就是你想要得到的年份。 月需要減1,日可以直接插入。 這種方法用的比

Java常量池

在Java的記憶體分配中,總共3種常量池: 轉發連結 :https://blog.csdn.net/zm13007310400/article/details/77534349 1.字串常量池(String Constant Pool): 1.1:字串常量池在Java記憶體區域的哪個位

java static 作用

     static表示“全域性”或者“靜態”的意思,用來修飾成員變數和成員方法,也可以形成靜態static程式碼塊,但是Java語言中沒有全域性變數的概念。 被static修飾的成員變數和成員方法獨立於該類的任何物件。也就是說,它不依賴

Java 的Properties

一、Java Properties類     Java中有個比較重要的類Properties(Java.util.Properties),主要用於讀取Java的配置檔案,各種語言都有自己所支援的配置檔案,配置檔案中很多變數是經常改變的,這樣做也是為了方便使用者,讓使

Java的Type

轉載自逆水行舟的部落格Java中的Type詳解 本文主要介紹java中Type介面的來歷以及相關的幾個介面。 通過這邊文章,我們可以瞭解到與範型相關的幾個介面, 對範型的分類有個瞭解; 還可以瞭解到Type介面與Class類的關係, 以及Type出現的原因. 反射相關介面