轉自:http://blog.csdn.net/dfdsggdgg/article/details/51543545
sun.misc.Unsafe包下載
http://download.csdn.net/detail/dfdsggdgg/9535347
實例化私有類
正常情況下沒法實例化一個私有構造函數的類,但是Unsafe可以做到。
import java.lang.reflect.Field;
import sun.misc.Unsafe;
public class UnsafePlayer {
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.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;
}
}
cas原子級操作&&通過內存偏移地址修改變量值
import java.lang.reflect.Field;
import sun.misc.Unsafe;
public class UnsafePlayer {
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()+":對應的內存偏移地址"+unsafe.objectFieldOffset(field));
}
System.out.println("-------------------");
int ageOffset= 8;
//修改內存偏移地址爲8的值(age),返回true,說明通過內存偏移地址修改age的值成功
System.out.println(unsafe.compareAndSwapInt(player, ageOffset, 18, 20));
System.out.println("age修改後的值:"+player.getAge());
System.out.println("-------------------");
//修改內存偏移地址爲8的值,但是修改後不保證立馬能被其他的線程看到。
unsafe.putOrderedInt(player, 8, 33);
System.out.println("age修改後的值:"+player.getAge());
System.out.println("-------------------");
//修改內存偏移地址爲12的值,volatile修飾,修改能立馬對其他線程可見
unsafe.putObjectVolatile(player, 12, "han mei");
System.out.println("name修改後的值:"+unsafe.getObjectVolatile(player, 12));
}
}
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;
}
}
創建超級數組
java中數組的最大長度爲Integer.MAX_VALUE,正常情況下如果想創建一個大於Integer.MAX_VALUE的數組是做不到的,但是Unsafe可以,通過對內存進行直接分配實現。
import java.lang.reflect.Field;
import sun.misc.Unsafe;
public class SuperArray {
public static void main(String[] arg) throws Exception{
//通過反射實例化Unsafe
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
Unsafe unsafe = (Unsafe) f.get(null);
//只要內存夠大,可以把這個調大,大於Integer.MAX_VALUE
long size = (long)Integer.MAX_VALUE/2 ;
long addr = unsafe.allocateMemory(size);
System.out.println("unsafe address :"+addr);
for (int i = 0; i < size; i++) {
unsafe.putByte(addr+i, (byte)6);
if(unsafe.getByte(addr+i) !=6){
System.out.println("failed at offset");
}
}
}
}
把size調大,size = (long)Integer.MAX_VALUE*2,錯誤信息如下。
unsafe address :15817328
#
# A fatal error has been detected by the Java Runtime Environment:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x61cc0350, pid=31240, tid=31324
#
# JRE version: Java(TM) SE Runtime Environment (8.0_45-b14) (build 1.8.0_45-b14)
# Java VM: Java HotSpot(TM) Client VM (25.45-b02 mixed mode windows-x86 )
# Problematic frame:
# V[thread 30484 also had an error]
[jvm.dll+0x40350]
#
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
#
# An error report file with more information is saved as:
# C:\welab\workspace\Person\hs_err_pid31240.log
線程掛起與恢復
將一個線程進行掛起是通過park方法實現的,調用 park後,線程將一直阻塞直到超時或者中斷等條件出現。unpark可以終止一個掛起的線程,使其恢復正常。整個併發框架中對線程的掛起操作被封裝在 LockSupport類中,LockSupport類中有各種版本pack方法,但最終都調用了Unsafe.park()方法。
public class LockSupport {
/**
* 恢復阻塞線程
*/
public static void unpark(Thread thread) {
if (thread != null)
unsafe.unpark(thread);
}
/**
* 一直阻塞當前線程,調用Unsafe.park()方法
*/
public static void park(Object blocker) {
Thread t = Thread.currentThread();
setBlocker(t, blocker);
unsafe.park(false, 0L);
setBlocker(t, null);
}
/**
* 阻塞當前線程nanos納秒
*/
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);
}
/**
* 阻塞當前線程nanos納秒
*/
public static void parkNanos(long nanos) {
if (nanos > 0)
unsafe.park(false, nanos);
}
public static void parkUntil(long deadline) {
unsafe.park(true, deadline);
}
}
最後看下阻塞和恢復的例子
import java.util.concurrent.locks.LockSupport;
public class Lock {
public static void main(String[] args) throws InterruptedException {
ThreadPark threadPark = new ThreadPark();
threadPark.start();
ThreadUnPark threadUnPark = new ThreadUnPark(threadPark);
threadUnPark.start();
//等待threadUnPark執行成功
threadUnPark.join();
System.out.println("運行成功....");
}
static class ThreadPark extends Thread{
public void run(){
System.out.println(Thread.currentThread() +"我將被阻塞在這了60s....");
//阻塞60s,單位納秒 1s = 1000000000
LockSupport.parkNanos(1000000000l*60);
System.out.println(Thread.currentThread() +"我被恢復正常了....");
}
}
static class ThreadUnPark extends Thread{
public Thread thread = null;
public ThreadUnPark(Thread thread){
this.thread = thread;
}
public void run(){
System.out.println("提前恢復阻塞線程ThreadPark");
//恢復阻塞線程
LockSupport.unpark(thread);
}
}
}