三.多线程JUC篇-3.1 Unsafe

1.java如何手工管理内存

  • Java和C++语言的一个重要区别就是Java中我们无法直接操作一块内存区域,不能像C++中那样可以自己申请内存和释放内存。Java中的Unsafe类为我们提供了类似C++手动管理内存的能力。
  • Unsafe类,全限定名是sun.misc.Unsafe,从名字中我们可以看出来这个类对普通程序员来说是“危险”的,一般应用开发者不会用到这个类。

2.如何获取Unsafe实例

  • Unsafe类是"final"的,不允许继承。且构造函数是private的:
public final class Unsafe {
    private static final Unsafe theUnsafe;
    public static final int INVALID_FIELD_OFFSET = -1;

    private static native void registerNatives();
    // 构造函数是private的,不允许外部实例化
    private Unsafe() {
    }
    ...
}

      因此我们无法在外部对Unsafe进行实例化。 

  • 获取Unsafe

       Unsafe无法实例化,那么怎么获取Unsafe呢?答案就是通过反射来获取Unsafe:

public Unsafe getUnsafe() throws IllegalAccessException {
    Field unsafeField = Unsafe.class.getDeclaredFields()[0];
    unsafeField.setAccessible(true);
    Unsafe unsafe = (Unsafe) unsafeField.get(null);
    return unsafe;
}

3. Unsafe是什么?

  • Java 无法直接访问底层操作系统,而是通过本地(native)方法来访问。不过尽管如此,JVM 还是开了一个后门,JDK 中有一个类 Unsafe,底层是使用C/C++写的,它提供了硬件级别的原子操作。Unsafe为我们提供了访问底层的机制,这种机制仅供java核心类库使用,而不应该被普通用户使用。
  • UnSafe的功能主要有:(1) 实例化一个类;(2) 修改私有字段的值;(3) 抛出checked异常;(4) 使用堆外内存;(5) CAS操作;(6) 阻塞/唤醒线程;(7) 内存屏障


4. Unsafe中的CAS操作

  • JUC中用到了大量的CAS,他们的底层其实都是采用Unsafe的CAS操作
  • CAS(比较与交换,Compare and swap)是一种有名的无锁算法,因为不需要加锁,性能比加锁高。CAS是一个CPU指令,CAS还是一个乐观锁技术
  • CAS存在的问题:

        i. 经典的ABA问题,危害有(以栈举例),解决方案:版本号控制,有的数据结构在高位用邮戳标记;不重复使用节点引用,而是构建新的节点
        ii. CAS常常搭配自旋一起使用,如果自选长时间不成功,循环时间长 开销大
        iii. 只能保持一个共享变量的安全操作

5. Unsafe的阻塞/唤醒操作
    LockSupport类中的park与unpark方法对unsafe中的park与unpark方法做了封装,LockSupport类中有各种版本pack方法,但最终都调用了Unsafe.park()方法

6. 实例化类的六种方式
    a. 通过构造方法new一个对象
    b. 通过Class实例一个类,Class.forName("包名.类名").newInstance()
    c. 通过反射实例化一个类,class.newInstance()
    d. 通过克隆,需实现Cloneable接口,或覆盖Object中的clone()方法
    e. 通过反序列化
    f. 通过Unsafe实例化一个类,unsafe.allocateInstance(xxx.class)

7.例子

(1)Unsafe CAS

public class UnsafeCounter {
    public static void main(String[] args) throws Exception {
        
        ExecutorService service = Executors.newFixedThreadPool(1000);
        //CASCounter result: 1000000, Timer passed ms: 137
        //AtomicCounter result: 1000000. Timer passed ms: 153
        //LockCounter result: 1000000. Timer passed ms: 175
        //SynCounter result: 1000000. Timer passed ms: 159
        //StupidCounter result: 946790. Timer passed ms: 158

        Counter counter = new StupidCounter();
        long start=System.currentTimeMillis();
        for (int i = 0; i < 1000; i++) {
            service.execute(new CounterRunnable(counter, 1000));

        }

        service.shutdown();
        service.awaitTermination(1, TimeUnit.HOURS);
        long end = System.currentTimeMillis();

        System.out.println("Counter result: " + counter.getCounter() + ". Timer passed ms: " + (end - start));

    }

    public static Unsafe getUnsafe(){
        try {
            Field unsafe =  Unsafe.class.getDeclaredField("theUnsafe");
            unsafe.setAccessible(true);
            return (Unsafe)unsafe.get(null);

        } catch (Exception e) {
            e.printStackTrace();
            throw  new RuntimeException("get unsafe object failed");
        }

    }

    interface Counter{
        void increment();
        long getCounter();
    }

    static class StupidCounter implements Counter{
        private volatile long counter = 0;

        @Override
        public void increment() {
            counter++;
        }

        @Override
        public long getCounter() {
            return counter;
        }
    }

    static  class SynCounter implements Counter{
        private long counter = 0;

        @Override
        public synchronized void increment() {
            counter++;
        }

        @Override
        public long getCounter() {
            return counter;
        }
    }

    static class LockCounter implements Counter{
        private long counter = 0;
        private final Lock lock = new ReentrantLock();

        @Override
        public void increment() {
            try{
                lock.lock();
                counter++;
            }finally {
                lock.unlock();
            }
        }

        @Override
        public long getCounter() {
            return counter;
        }
    }

    static class AtomicCounter implements Counter{
        private AtomicLong counter = new AtomicLong();

        @Override
        public void increment() {
            counter.getAndIncrement();
        }

        @Override
        public long getCounter() {
            return counter.get();
        }
    }

    static  class CASCounter implements Counter{
        private volatile  long counter = 0;
        private Unsafe unsafe;
        private long offset;

        CASCounter() throws NoSuchFieldException {
            unsafe = getUnsafe();
            offset = unsafe.objectFieldOffset(CASCounter.class.getDeclaredField("counter"));

        }

        @Override
        public void increment() {
            long current = counter;
            while (!unsafe.compareAndSwapLong(this, offset, current, current+1)){
                current = counter;
            }
        }

        @Override
        public long getCounter() {
            return counter;
        }
    }
    static class CounterRunnable implements Runnable{
        private final Counter counter;
        private final int num;

        public CounterRunnable(Counter counter, int num) {
            this.counter = counter;
            this.num = num;
        }

        @Override
        public void run() {
            for (int i = 0; i < this.num; i++) {
                counter.increment();
            }
        }
    }
}

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值