Unsafe介绍以及几种Counter方案性能对比

2019-04-16  本文已影响0人  yincb

一 、Unsafe介绍

1.1 作用

可以用来在任意内存地址位置处读写数据,支持一些CAS原子操作
Java最初被设计为一种安全的受控环境。尽管如此,HotSpot还是包含了一个后门sun.misc.Unsafe,提供了一些可以直接操控内存和线程的底层操作。Unsafe被JDK广泛应用于java.nio和并发包等实现中,这个不安全的类提供了一个观察HotSpot JVM内部结构并且可以对其进行修改,但是不建议在生产环境中使用

1.2 获取Unsafe实例

Unsafe对象不能直接通过new Unsafe()或调用Unsafe.getUnsafe()获取,
原因如下:
不能直接new Unsafe(),原因是Unsafe被设计成单例模式,构造方法是私有的;
不能通过调用Unsafe.getUnsafe()获取,因为getUnsafe被设计成只能从引导类加载器(bootstrap class loader)加载

private static Unsafe getUnsfe(){
        try {
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            return (Unsafe) field.get(null);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

二、几种Counter方案性能对比

public class UnsafeTest {

    public static void main(String[] args) throws Exception {
        ExecutorService service = Executors.newFixedThreadPool(1000);
        /**
         * StupiedCounter
         *      counter:9955671
         *      time:334
         */
        //Counter counter = new StupiedCounter();

        /**
         * SyncCounter
         *      counter:10000000
         *      time:1878
         */
        //Counter counter = new SyncCounter();

        /**
         * LockCounter
         *      counter:10000000
         *      time:413
         */
        // Counter counter = new LockCounter();

        /**
         * AtomicCounter
         *      counter:10000000
         *      time:287
         */
        // Counter counter = new AtomicCounter();

        /**
         * CasCounter
         *      counter:10000000
         *      time:638
         */
        Counter counter = new CasCounter();

        long start = System.currentTimeMillis();
        for (int i = 0; i < 1000; i++) {
            service.submit(new CounterRunner(counter,10000));
        }
        service.shutdown();
        service.awaitTermination(1, TimeUnit.HOURS);
        long end = System.currentTimeMillis();
        System.out.println("counter:"+counter.getCounter());
        System.out.println("time:"+(end-start));
    }

    private static Unsafe getUnsfe(){
        try {
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            return (Unsafe) field.get(null);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    static class StupiedCounter implements Counter{
        private long counter = 0;
        @Override
        public void increment() {
            counter++;
        }
        @Override
        public long getCounter() {
            return counter;
        }
    }

    static class SyncCounter 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 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.incrementAndGet();
        }
        @Override
        public long getCounter() {
            return counter.get();
        }
    }

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

        public CasCounter() throws NoSuchFieldException {
            this.unsafe = getUnsfe();
            this.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;
        }
    }

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

    static class CounterRunner implements Runnable{

        private final Counter counter;
        private final int num;

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

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

}
上一篇下一篇

猜你喜欢

热点阅读