Unsafe是位於sun.misc包下的一個類,主要提供一些用於執行低級別、不安全操作的方法,如直接訪問系統內存資源、自主管理內存資源等,這些方法在提升Java運行效率、增強Java語言底層資源操作能力方面起到了很大的作用。但由於Unsafe類使Java語言擁有了類似C語言指針一樣操作內存空間的能力,這無疑也增加了程序發生相關指針問題的風險。在程序中過度、不正確使用Unsafe類會使得程序出錯的概率變大,使得Java這種安全的語言變得不再「安全」,因此對Unsafe的使用一定要慎重。
使用Unsafe申請的內存是對外內存。
示例介紹如何使用
public static void main(String[] args) throws Exception {
Num num1 = new Num(); System.err.println("new關鍵字創建: n=" + num1.getN());
Num num2 = Num.class.newInstance(); System.err.println("反射創建: n=" + num2.getN()); Unsafe unsafe = getUnsafe(); Num num3 = (Num) unsafe.allocateInstance(Num.class); System.err.println("反射創建: n=" + num3.getN());
Field nField = num3.getClass().getDeclaredField("n"); unsafe.putInt(num3, unsafe.objectFieldOffset(nField), 2);
System.err.println("Unsafe 修改後的值: n=" + num3.getN());
byte[] bytes = getClazzContent(); Class numClazz = unsafe.defineClass(null, bytes, 0, bytes.length, null, null); Object result = numClazz.getMethod("getN").invoke(numClazz.newInstance());
System.err.println("Unsafe 加載Num.class文件: n=" + result); }
public static Unsafe getUnsafe() { Field f; Unsafe unsafe; try { f = Unsafe.class.getDeclaredField("theUnsafe"); f.setAccessible(true); unsafe = (Unsafe) f.get(null); } catch (Exception e) { throw new RuntimeException("initial the unsafe failure..."); } return unsafe; }
public static byte[] getClazzContent() throws IOException { File f = new File("/usr/local/gitrep/banyan/target/classes/org/banyan/concurrent/base/UnsafeDemo$Num.class"); try (FileInputStream fis = new FileInputStream(f)) { byte[] bytes = new byte[fis.available()]; fis.read(bytes); return bytes; } }
public static class Num { private int n;
public Num() { this.n = 1; }
public int getN() { return n; }
public void setN(int n) { this.n = n; } }運行結果如下
new關鍵字創建: n=1反射創建: n=1Unsafe創建: n=0Unsafe 修改後的值: n=2Unsafe 加載Num.class文件: n=1從運行結果可以看出,Unsafe的使用,後續在詳細介紹