UnSafe学习笔记

前言

  1. 锁会导致线程上下文切换和重新调度开销
  2. volatile只能保证共享变量的可见性,不能解决读-改-写等的原子性问题
  3. CAS(Compare and Swap)是JDK提供的非阻塞原子性操作,通过硬件保证了比较-更新操作的原子性

Synchronized

又名监视器锁,释放该锁场景:

  1. 正常退出同步代码块
  2. 抛出异常后
  3. 同步块内调用了该内置锁资源的wait方法时

synchronized内存语义:进入synchronized内使用的共享变量从线程工作内存中清除,这样将会从主内存中去取;退出synchronized会将本地内存修改的共享变量刷新到主内存。

volatile

volatile具有可见性但不具有原子性

CAS

JDK的rt.jar包中的Unsafe类提供了硬件级别的原子性操作,内部提供了一系列原子操作方法,如:

http://hg.openjdk.java.net/jdk8/jdk8/jdk/file/687fd7c7986d/src/share/classes/sun/misc/Unsafe.java

/*
	o:对象内存地址
	offset:对象中变量偏移量
	expected:变量预期值
	update:新更新的值
	方法含义:比较对象o中偏移量为offset的变量值是否与expect相等,相等则使用update值更新,然后返回true,否则返回false
*/
public final native boolean compareAndSwapLong(Object o, long offset,
                                                      long expected,
                                                      long x);
/*
	获取对象o中偏移量为offset的变量对应volatile语义的值
/*
public native long getLongVolatile(Object o, long offset);
//JDK8新增函数
/*
	获取对象obj中偏移量为offset的变量volatile语义的当前值,并设置变量volatile语义的值为update
*/
public final long getAndSetLong(Object obj, long offset, long update) 
/*
	获取对象obj中偏移量为offset的变量volatile语义的当前值,并设置变量值为原始值+addValue
*/
public final long getAndAddLong(Object obj,long offset, long addValue)

Unsafe对象不能通过getUnsafe方法得到

public static Unsafe getUnsafe() {
        Class<?> caller = Reflection.getCallerClass();
    	//如果不是BootStrap类加载器加载则抛出异常
        if (!VM.isSystemDomainLoader(caller.getClassLoader()))
            throw new SecurityException("Unsafe");
        return theUnsafe;
}
//判断paramClassLoader是不是BootStrap类加载器
public static boolean isSystemDomainLoader(ClassLoader paramClassLoader) {
    return paramClassLoader == null;
}

为什么要加这个判断?因为我们在main函数所在的类是AppClassLoader加载的,所以在main函数里面加载Unsafe类时,根据委托机制会委托BootStrap去加载Unsafe类。如果没有这个限制,我们的应用程序可以随意使用Unsafe类,而Unsafe类可以直接操作内存,这是不安全的。

当然如果要使用这个类则需要通过反射来得到,如:

Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe)field.get(null);

你可能感兴趣的:(java)