使用unsafe时的坑

直接调用Unsafe中的getUnsafe()的方法获取Unsafe时候是不会报错的,但是运行的时候就会报错,如下:

编译启动的时候,会报错,不是安全的类
进入getUnsafe()方法中:

var0是当前调用当前方法的类的class,var0.getClassLoader()方法获取的是当前类的加载器AppClassLoader:

获取出加载器的时候进入方法isSystemDomainLoader(ClassLoader var0)进行判断,这个判断返回是false,则getsafe()方法中的判断则是true,则抛出异常:

所以只能用BootstrapClassLoader加载器中调用的类使用这个unsage,比如concurrenthashmap是在BootstrapClassLoader中加载的,getClassLoader0()获取出来是为null的,所以不会抛出异常。因为Unsafe中有个theUnsafe的属性,所以可以通过放射来获取这个已经实例化的对象属性,从而获得unsafe对象:

/**
 * Unsafe 类是直接操作操作系统的,所以是不安全的类,不允许自己new
 */
public class UnSafeTest {

    private int i = 0;
    private static Unsafe unsafe;
    //偏移量,unsafe方法中会使用到
    private static long COUNT_OFFSET;

    static {
        //不能直接new,会报错
        //unsafe = Unsafe.getUnsafe();
        //Unsafe类中有一个熟悉private static final Unsafe theUnsafe; 内部通过new实例化了,所以
        // 可以通过反射类获取这个属性,从而获取unsfe
        try {
            //获取属性
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            unsafe = (Unsafe) field.get(null);

            //获取i属性字段的偏移量
            COUNT_OFFSET = unsafe.objectFieldOffset(UnSafeTest.class.getDeclaredField("i"));
        } catch (IllegalAccessException | NoSuchFieldException e) {
            e.printStackTrace();
        }
    }


public static void main(String[] args) {
        UnSafeTest unSafeTest =  new UnSafeTest();
        //创建两个线程来操作变量i
        new Thread(new Runnable() {
            @Override
            public void run() {
               //修改unsafe对象中偏移量为COUNT_OFFSET属性的值,如果unSafeTest.i跟内存中的值一致,说明还没被修改
                //则进行加1操作,如果不一致,则不进行操作
                boolean b = unsafe.compareAndSwapInt(unSafeTest, COUNT_OFFSET, unSafeTest.i, unSafeTest.i + 1);
                if (b){
                   System.out.println(unsafe.getIntVolatile(unSafeTest, COUNT_OFFSET));
                }

            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                boolean b = unsafe.compareAndSwapInt(unSafeTest, COUNT_OFFSET, unSafeTest.i, unSafeTest.i + 1);
                if (b){
                    System.out.println(unsafe.getIntVolatile(unSafeTest, COUNT_OFFSET));
                }

            }
        }).start();


    }
    
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值