前言
本文主要給大家介紹了關(guān)于java中unsafe類的相關(guān)內(nèi)容,分享出來供大家參考學(xué)習(xí),下面話不多說了,來一起看看詳細(xì)的介紹吧
1.unsafe類介紹
unsafe類是在sun.misc包下,不屬于java標(biāo)準(zhǔn)。但是很多java的基礎(chǔ)類庫,包括一些被廣泛使用的高性能開發(fā)庫都是基于unsafe類開發(fā)的,比如netty、hadoop、kafka等。
使用unsafe可用來直接訪問系統(tǒng)內(nèi)存資源并進(jìn)行自主管理,unsafe類在提升java運(yùn)行效率,增強(qiáng)java語言底層操作能力方面起了很大的作用。
unsafe可認(rèn)為是java中留下的后門,提供了一些低層次操作,如直接內(nèi)存訪問、線程調(diào)度等。
官方并不建議使用unsafe。
下面是使用unsafe的一些例子。
1.1實(shí)例化私有類
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
import java.lang.reflect.field; import sun.misc.unsafe; public class unsafeplayer { public static void main(string[] args) throws exception { //通過反射實(shí)例化unsafe field f = unsafe. class .getdeclaredfield( "theunsafe" ); f.setaccessible( true ); unsafe unsafe = (unsafe) f.get( null ); //實(shí)例化player player player = (player) unsafe.allocateinstance(player. class ); player.setname( "li lei" ); system.out.println(player.getname()); } } class player{ private string name; private player(){} public string getname() { return name; } public void setname(string name) { this .name = name; } } |
1.2cas操作,通過內(nèi)存偏移地址修改變量值
java并發(fā)包中的synchronousqueue中的transferstack中使用cas更新棧頂。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
/ unsafe mechanics private static final sun.misc.unsafe unsafe; private static final long headoffset; static { try { unsafe = sun.misc.unsafe.getunsafe(); class <?> k = transferstack. class ; headoffset = unsafe.objectfieldoffset (k.getdeclaredfield( "head" )); } catch (exception e) { throw new error(e); } } //棧頂 volatile snode head; //更新棧頂 boolean cashead(snode h, snode nh) { return h == head && unsafe.compareandswapobject( this , headoffset, h, nh); } |
1.3直接內(nèi)存訪問
unsafe的直接內(nèi)存訪問:用unsafe開辟的內(nèi)存空間不占用heap空間,當(dāng)然也不具有自動內(nèi)存回收功能。做到像c一樣自由利用系統(tǒng)內(nèi)存資源。
2.unsafe類源碼分析
unsafe的大部分api都是native的方法,主要包括以下幾類:
1)class相關(guān)。主要提供class和它的靜態(tài)字段的操作方法。
2)object相關(guān)。主要提供object和它的字段的操作方法。
3)arrray相關(guān)。主要提供數(shù)組及其中元素的操作方法。
4)并發(fā)相關(guān)。主要提供低級別同步原語,如cas、線程調(diào)度、volatile、內(nèi)存屏障等。
5)memory相關(guān)。提供了直接內(nèi)存訪問方法(繞過java堆直接操作本地內(nèi)存),可做到像c一樣自由利用系統(tǒng)內(nèi)存資源。
6)系統(tǒng)相關(guān)。主要返回某些低級別的內(nèi)存信息,如地址大小、內(nèi)存頁大小。
2.1class相關(guān)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
//靜態(tài)屬性的偏移量,用于在對應(yīng)的class對象中讀寫靜態(tài)屬性 public native long staticfieldoffset(field f); public native object staticfieldbase(field f); //判斷是否需要初始化一個類 public native boolean shouldbeinitialized( class <?> c); //確保類被初始化 public native void ensureclassinitialized( class <?> c); //定義一個類,可用于動態(tài)創(chuàng)建類 public native class <?> defineclass(string name, byte [] b, int off, int len, classloader loader, protectiondomain protectiondomain); //定義一個匿名類,可用于動態(tài)創(chuàng)建類 public native class <?> defineanonymousclass( class <?> hostclass, byte [] data, object[] cppatches); |
2.2object相關(guān)
java中的基本類型(boolean、byte、char、short、int、long、float、double)及對象引用類型都有以下方法。
1
2
3
4
5
6
|
//獲得對象的字段偏移量 public native long objectfieldoffset(field f); //獲得給定對象地址偏移量的int值 public native int getint(object o, long offset); //設(shè)置給定對象地址偏移量的int值 public native void putint(object o, long offset, int x); |
1
2
3
|
//創(chuàng)建對象,但并不會調(diào)用其構(gòu)造方法。如果類未被初始化,將初始化類。 public native object allocateinstance( class <?> cls) throws instantiationexception; |
2.3數(shù)組相關(guān)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
/** * report the offset of the first element in the storage allocation of a * given array class. if {@link #arrayindexscale} returns a non-zero value * for the same class, you may use that scale factor, together with this * base offset, to form new offsets to access elements of arrays of the * given class. * * @see #getint(object, long) * @see #putint(object, long, int) */ //返回數(shù)組中第一個元素的偏移地址 public native int arraybaseoffset( class <?> arrayclass); //boolean、byte、short、char、int、long、float、double,及對象類型均有以下方法 /** the value of {@code arraybaseoffset(boolean[].class)} */ public static final int array_boolean_base_offset = theunsafe.arraybaseoffset( boolean []. class ); /** * report the scale factor for addressing elements in the storage * allocation of a given array class. however, arrays of "narrow" types * will generally not work properly with accessors like {@link * #getbyte(object, int)}, so the scale factor for such classes is reported * as zero. * * @see #arraybaseoffset * @see #getint(object, long) * @see #putint(object, long, int) */ //返回數(shù)組中每一個元素占用的大小 public native int arrayindexscale( class <?> arrayclass); //boolean、byte、short、char、int、long、float、double,及對象類型均有以下方法 /** the value of {@code arrayindexscale(boolean[].class)} */ public static final int array_boolean_index_scale = theunsafe.arrayindexscale( boolean []. class ); |
通過arraybaseoffset和arrayindexscale可定位數(shù)組中每個元素在內(nèi)存中的位置。
2.4并發(fā)相關(guān)
2.4.1cas相關(guān)
cas:compareandswap,內(nèi)存偏移地址offset,預(yù)期值expected,新值x。如果變量在當(dāng)前時刻的值和預(yù)期值expected相等,嘗試將變量的值更新為x。如果更新成功,返回true;否則,返回false。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
//更新變量值為x,如果當(dāng)前值為expected //o:對象 offset:偏移量 expected:期望值 x:新值 public final native boolean compareandswapobject(object o, long offset, object expected, object x); public final native boolean compareandswapint(object o, long offset, int expected, int x); public final native boolean compareandswaplong(object o, long offset, long expected, long x); |
從java 8開始,unsafe中提供了以下方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
//增加 public final int getandaddint(object o, long offset, int delta) { int v; do { v = getintvolatile(o, offset); } while (!compareandswapint(o, offset, v, v + delta)); return v; } public final long getandaddlong(object o, long offset, long delta) { long v; do { v = getlongvolatile(o, offset); } while (!compareandswaplong(o, offset, v, v + delta)); return v; } //設(shè)置 public final int getandsetint(object o, long offset, int newvalue) { int v; do { v = getintvolatile(o, offset); } while (!compareandswapint(o, offset, v, newvalue)); return v; } public final long getandsetlong(object o, long offset, long newvalue) { long v; do { v = getlongvolatile(o, offset); } while (!compareandswaplong(o, offset, v, newvalue)); return v; } public final object getandsetobject(object o, long offset, object newvalue) { object v; do { v = getobjectvolatile(o, offset); } while (!compareandswapobject(o, offset, v, newvalue)); return v; |
2.4.2線程調(diào)度相關(guān)
1
2
3
4
5
6
7
8
9
10
|
//取消阻塞線程 public native void unpark(object thread); //阻塞線程 public native void park( boolean isabsolute, long time); //獲得對象鎖 public native void monitorenter(object o); //釋放對象鎖 public native void monitorexit(object o); //嘗試獲取對象鎖,返回true或false表示是否獲取成功 public native boolean trymonitorenter(object o); |
2.4.3volatile相關(guān)讀寫
java中的基本類型(boolean、byte、char、short、int、long、float、double)及對象引用類型都有以下方法。
1
2
3
4
5
6
7
|
//從對象的指定偏移量處獲取變量的引用,使用volatile的加載語義 //相當(dāng)于getobject(object, long)的volatile版本 public native object getobjectvolatile(object o, long offset); //存儲變量的引用到對象的指定的偏移量處,使用volatile的存儲語義 //相當(dāng)于putobject(object, long, object)的volatile版本 public native void putobjectvolatile(object o, long offset, object x); |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
/** * version of {@link #putobjectvolatile(object, long, object)} * that does not guarantee immediate visibility of the store to * other threads. this method is generally only useful if the * underlying field is a java volatile (or if an array cell, one * that is otherwise only accessed using volatile accesses). */ public native void putorderedobject(object o, long offset, object x); /** ordered/lazy version of {@link #putintvolatile(object, long, int)} */ public native void putorderedint(object o, long offset, int x); /** ordered/lazy version of {@link #putlongvolatile(object, long, long)} */ public native void putorderedlong(object o, long offset, long x); |
2.4.4內(nèi)存屏障相關(guān)
java 8引入 ,用于定義內(nèi)存屏障,避免代碼重排序。
1
2
3
4
5
6
|
//內(nèi)存屏障,禁止load操作重排序,即屏障前的load操作不能被重排序到屏障后,屏障后的load操作不能被重排序到屏障前 public native void loadfence(); //內(nèi)存屏障,禁止store操作重排序,即屏障前的store操作不能被重排序到屏障后,屏障后的store操作不能被重排序到屏障前 public native void storefence(); //內(nèi)存屏障,禁止load、store操作重排序 public native void fullfence(); |
2.5直接內(nèi)存訪問(非堆內(nèi)存)
allocatememory所分配的內(nèi)存需要手動free(不被gc回收)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
//(boolean、byte、char、short、int、long、float、double)都有以下get、put兩個方法。 //獲得給定地址上的int值 public native int getint( long address); //設(shè)置給定地址上的int值 public native void putint( long address, int x); //獲得本地指針 public native long getaddress( long address); //存儲本地指針到給定的內(nèi)存地址 public native void putaddress( long address, long x); //分配內(nèi)存 public native long allocatememory( long bytes); //重新分配內(nèi)存 public native long reallocatememory( long address, long bytes); //初始化內(nèi)存內(nèi)容 public native void setmemory(object o, long offset, long bytes, byte value); //初始化內(nèi)存內(nèi)容 public void setmemory( long address, long bytes, byte value) { setmemory( null , address, bytes, value); } //內(nèi)存內(nèi)容拷貝 public native void copymemory(object srcbase, long srcoffset, object destbase, long destoffset, long bytes); //內(nèi)存內(nèi)容拷貝 public void copymemory( long srcaddress, long destaddress, long bytes) { copymemory( null , srcaddress, null , destaddress, bytes); } //釋放內(nèi)存 public native void freememory( long address); |
2.6系統(tǒng)相關(guān)
1
2
3
4
5
6
7
8
|
//返回指針的大小。返回值為4或8。 public native int addresssize(); /** the value of {@code addresssize()} */ public static final int address_size = theunsafe.addresssize(); //內(nèi)存頁的大小。 public native int pagesize(); |
3.參考資料
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對服務(wù)器之家的支持。
原文鏈接:https://www.cnblogs.com/yeyang/p/9074894.html