java 生態(tài)圈物喷。 幾乎每個使用 java開發(fā)的工具、軟件基礎(chǔ)設(shè)施、高性能開發(fā)庫都在底層使用了 sun.misc.Unsafe 欺殿。這就是SUN未開源的sun.misc.Unsafe的類橡娄,該類功能很強大诗箍,涉及到類加載機制,其實例一般情況是獲取不到的挽唉,源碼中的設(shè)計是采用單例模式滤祖,不是系統(tǒng)加載初始化就會拋出SecurityException異常。Unsafe類官方并不對外開放瓶籽,因為Unsafe這個類提供了一些繞開JVM的更底層功能匠童,基于它的實現(xiàn)可以提高效率。
Unsafe API的大部分方法都是native實現(xiàn)
分為下面幾類:
Info:主要返回某些低級別的內(nèi)存信息:
public native int addressSize();
public native int pageSize();
Objects:主要提供Object和它的域操縱方法
public native Object allocateInstance(Class<?> var1) throws InstantiationException;
public native long objectFieldOffset(Field var1);
Class:主要提供Class和它的靜態(tài)域操縱方
public native long staticFieldOffset(Field var1);
public native Class<?> defineClass(String var1, byte[] var2, int var3, int var4, ClassLoader var5, ProtectionDomain var6);
public native Class<?> defineAnonymousClass(Class<?> var1, byte[] var2, Object[] var3);
public native void ensureClassInitialized(Class<?> var1);
Arrays:數(shù)組操縱方法
public native int arrayBaseOffset(Class<?> var1);
public native int arrayIndexScale(Class<?> var1);
Synchronization:主要提供低級別同步原語
/** @deprecated */
@Deprecated
public native void monitorEnter(Object var1);
/** @deprecated */
@Deprecated
public native void monitorExit(Object var1);
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
public native void putOrderedInt(Object var1, long var2, int var4);
Memory:直接內(nèi)存訪問方法(繞過JVM堆直接操縱本地內(nèi)存)
public native long allocateMemory(long var1);
public native long reallocateMemory(long var1, long var3);
public native void setMemory(Object var1, long var2, long var4, byte var6);
public native void copyMemory(Object var1, long var2, Object var4, long var5, long var7);
Unsafe類實例的獲取
Unsafe類設(shè)計只提供給JVM信任的啟動類加載器所使用塑顺,是一個典型的單例模式類
private Unsafe() {
}
@CallerSensitive
public static Unsafe getUnsafe() {
Class var0 = Reflection.getCallerClass();
if(!VM.isSystemDomainLoader(var0.getClassLoader())) {
throw new SecurityException("Unsafe");
} else {
return theUnsafe;
}
}
可以通過反射技術(shù)暴力獲取Unsafe對象汤求,下面做一個cas算法的測試
package unsafe;
import sun.misc.Unsafe;
import java.lang.reflect.Field;
public class UnsafeCASTest {
public static void main(String[] args) throws Exception {
// 通過反射實例化Unsafe
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
Unsafe unsafe = (Unsafe) f.get(null);
// 實例化Player
Player player = (Player) unsafe.allocateInstance(Player.class);
player.setAge(18);
player.setName("li lei");
for (Field field : Player.class.getDeclaredFields()) {
System.out.println(field.getName() + ":對應(yīng)的內(nèi)存偏移地址" + unsafe.objectFieldOffset(field));
}
System.out.println("-------------------");
// unsafe.compareAndSwapInt(arg0, arg1, arg2, arg3)
// arg0, arg1, arg2, arg3 分別是目標(biāo)對象實例,目標(biāo)對象屬性偏移量严拒,當(dāng)前預(yù)期值扬绪,要設(shè)的值
int ageOffset = 12;
// 修改內(nèi)存偏移地址為12的值(age),返回true,說明通過內(nèi)存偏移地址修改age的值成功
System.out.println(unsafe.compareAndSwapInt(player, ageOffset, 18, 20));
System.out.println("age修改后的值:" + player.getAge());
System.out.println("-------------------");
// 修改內(nèi)存偏移地址為12的值,但是修改后不保證立馬能被其他的線程看到裤唠。
unsafe.putOrderedInt(player, 12, 33);
System.out.println("age修改后的值:" + player.getAge());
System.out.println("-------------------");
// 修改內(nèi)存偏移地址為16的值挤牛,volatile修飾,修改能立馬對其他線程可見
unsafe.putObjectVolatile(player, 16, "han mei");
System.out.println("name修改后的值:" + unsafe.getObjectVolatile(player, 16));
}
}
class Player {
private int age;
private String name;
private Player() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
輸出的結(jié)果是:
age:對應(yīng)的內(nèi)存偏移地址12
name:對應(yīng)的內(nèi)存偏移地址16
-------------------
true
age修改后的值:20
-------------------
age修改后的值:33
-------------------
name修改后的值:han mei
在concurrent包是基于AQS (AbstractQueuedSynchronizer)框架的巧骚,AQS框架借助于兩個類:
Unsafe(提供CAS操作)
LockSupport(提供park/unpark操作)
歸根結(jié)底赊颠,LockSupport.park()和LockSupport.unpark(Thread thread)調(diào)用的是Unsafe中的native代碼:
//LockSupport中
public static void park() {
UNSAFE.park(false, 0L);
}
//LockSupport中
public static void unpark(Thread thread) {
if (thread != null)
UNSAFE.unpark(thread);
}
Unsafe類中的對應(yīng)方法:
//park
public native void park(boolean isAbsolute, long time);
//unpack
public native void unpark(Object var1);
park函數(shù)是將當(dāng)前調(diào)用Thread阻塞格二,而unpark函數(shù)則是將指定線程Thread喚醒。
Unsafe.park和Unsafe.unpark的底層實現(xiàn)原理
在Linux系統(tǒng)下竣蹦,是用的Posix線程庫pthread中的mutex(互斥量)顶猜,condition(條件變量)來實現(xiàn)的。
mutex和condition保護了一個_counter的變量痘括,當(dāng)park時长窄,這個變量被設(shè)置為0,當(dāng)unpark時纲菌,這個變量被設(shè)置為1挠日。
每個Java線程都有一個Parker實例,Parker類是這樣定義的:
class Parker : public os::PlatformParker {
private:
volatile int _counter ;
...
public:
void park(bool isAbsolute, jlong time);
void unpark();
...
}
class PlatformParker : public CHeapObj<mtInternal> {
protected:
pthread_mutex_t _mutex [1] ;
pthread_cond_t _cond [1] ;
...
}
可以看到Parker類實際上用Posix的mutex翰舌,condition來實現(xiàn)的嚣潜。
在Parker類里的_counter字段,就是用來記錄“許可”的椅贱。
當(dāng)調(diào)用park時懂算,先嘗試能否直接拿到“許可”,即_counter>0時庇麦,如果成功计技,則把_counter設(shè)置為0,并返回:
void Parker::park(bool isAbsolute, jlong time) {
// Ideally we'd do something useful while spinning, such
// as calling unpackTime().
// Optional fast-path check:
// Return immediately if a permit is available.
// We depend on Atomic::xchg() having full barrier semantics
// since we are doing a lock-free update to _counter.
if (Atomic::xchg(0, &_counter) > 0) return;
如果不成功山橄,則構(gòu)造一個ThreadBlockInVM垮媒,然后檢查_counter是不是>0,如果是航棱,則把_counter設(shè)置為0睡雇,unlock mutex并返回:
ThreadBlockInVM tbivm(jt);
if (_counter > 0) { // no wait needed
_counter = 0;
status = pthread_mutex_unlock(_mutex);
否則,再判斷等待的時間丧诺,然后再調(diào)用pthread_cond_wait函數(shù)等待入桂,如果等待返回奄薇,則把_counter設(shè)置為0驳阎,unlock mutex并返回:
if (time == 0) {
status = pthread_cond_wait (_cond, _mutex) ;
}
_counter = 0 ;
status = pthread_mutex_unlock(_mutex) ;
assert_status(status == 0, status, "invariant") ;
OrderAccess::fence();
unpark
當(dāng)unpark時,則簡單多了馁蒂,直接設(shè)置_counter為1呵晚,再unlock mutex返回。如果_counter之前的值是0沫屡,則還要調(diào)用pthread_cond_signal喚醒在park中等待的線程:
void Parker::unpark() {
int s, status ;
status = pthread_mutex_lock(_mutex);
assert (status == 0, "invariant") ;
s = _counter;
_counter = 1;
if (s < 1) {
if (WorkAroundNPTLTimedWaitHang) {
status = pthread_cond_signal (_cond) ;
assert (status == 0, "invariant") ;
status = pthread_mutex_unlock(_mutex);
assert (status == 0, "invariant") ;
} else {
status = pthread_mutex_unlock(_mutex);
assert (status == 0, "invariant") ;
status = pthread_cond_signal (_cond) ;
assert (status == 0, "invariant") ;
}
} else {
pthread_mutex_unlock(_mutex);
assert (status == 0, "invariant") ;
}
}