sun.misc.Unsafe的各种神技


1. sun.misc.Unsafe包下载



2. 实例化私有类


 正常情况下没法实例化一个私有构造函数的类,但是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;
	}
}

3. 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;
	}
	
}


3. 创建超级数组


    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


4.线程挂起与恢复


  将一个线程进行挂起是通过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);
		
	   }
   }
}



参考: http://blog.csdn.net/fenglibing/article/details/17138079   


  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: sun.misc.unsafe.park(native me) 是Java中的一个方法,它是用来阻塞当前线程的。具体来说,它会使当前线程进入等待状态,直到被唤醒或者被中断。这个方法通常用于实现线程的同步和互斥。 ### 回答2: sun.misc.unsafe.park(native me 是一个Java API中的方法,它通过使用Unsafepark方法来使当前线程进入休眠状态。在这个方法中,native关键字表示它是由本地代码实现的,也就是说具体的实现是由底层的操作系统提供的。 调用sun.misc.unsafe.park(native me 方法可以实现线程的等待和唤醒操作。当当前线程执行到这个方法时,会立即进入休眠状态,暂停自己的执行,直到其他线程通过调用Unsafeunpark方法唤醒它。 这个机制通常用于线程同步的场景,可以实现线程之间的协作。比如,一个生产者线程通过调用Unsafepark方法进入休眠状态,等待某个条件满足后再继续执行;而一个消费者线程在满足某个条件后,通过调用Unsafeunpark方法唤醒生产者线程,使其恢复执行。 需要注意的是,sun.misc.unsafe.park(native me 方法通常不建议直接使用,因为它是一个内部API,可能会在未来的版本中被移除或者修改。在实际应用中,可以使用更高级的并发工具,如Lock和Condition、CountDownLatch、Semaphore等来实现线程的等待和唤醒操作,这些API提供了更加安全和可靠的线程同步机制。 ### 回答3: sun.misc.unsafe.park(native me)是Java中的一个方法,它是由sun.misc.Unsafe提供的。该方法主要用于线程的阻塞等待。 在Java中,线程可以通过调用park方法进入阻塞状态,直到某个条件满足或者其他线程唤醒它。park方法是一种低级的阻塞机制,它不会占用CPU资源,因此适用于一些需要较长等待时间的场景。 使用park方法时,我们需要传入一个native me参数。native me是指要阻塞的线程对象,也就是当前执行park方法的线程自身。 park方法可以通过其他线程的unpark方法来唤醒被阻塞的线程。unpark方法会给指定的线程一个许可证,使得park方法立即返回。 使用park方法进行线程的阻塞等待可以提高线程的效率和性能,避免了一直占用CPU资源。 需要注意的是,sun.misc.unsafe.park(native me)方法属于sun.misc包下的不稳定的、不建议直接使用的API。在实际开发中,应该尽量避免使用这些API,而是使用Java提供的高级并发库,如java.util.concurrent包下的Locks和Conditions,或者使用更高层次的并发框架,如线程池。这些库和框架提供了更稳定、易用且可扩展的线程同步和阻塞等待机制。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值