使用Unsafe来实现自定义锁

1.使用Unsafe类

import sun.misc.Unsafe;

class UnsafePackage {
    private static Unsafe unsafe;

    static {
        try {
            Class<Unsafe> unsafeClass = Unsafe.class;
            Field theUnsafe = unsafeClass.getDeclaredField("theUnsafe");
            theUnsafe.setAccessible(true);
            unsafe = (Unsafe) theUnsafe.get(null);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public static Unsafe getUnsafe() {
        return unsafe;
    }
}

 

2.声明简单锁

class CustomLock {
    private volatile int status;

    private static Unsafe unsafe = UnsafePackage.getUnsafe();
    private static long statusOffset;
    private WaitingQueue queue = new WaitingQueue();

    static {
        try {
            statusOffset = unsafe.objectFieldOffset(CustomLock.class.getDeclaredField("status"));
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    private boolean comareAndSetStatus(int originalStatus, int updateStatus) {
        return unsafe.compareAndSwapInt(this, statusOffset, originalStatus, updateStatus);
    }

    public boolean lock() {
        if (comareAndSetStatus(0, 1)) {
            //System.out.println("竞争锁成功!继续执行后面的代码");
            return true;
        }

        //System.out.println("竞争锁失败!进入等待队列");
        push(Thread.currentThread());
        while (!comareAndSetStatus(0, 1)) {
            UnsafePackage.getUnsafe().park(false, 0);
        }
        return true;
    }

    public boolean unlock() {
        status = 0;
        Thread thread = pop();
        if (thread != null) {
            UnsafePackage.getUnsafe().unpark(thread);
        }
        return true;
    }

    private void push(Thread thread) {
        queue.push(thread);
    }

    private Thread pop() {
        return queue.pop();

    }
}

 

3.竞争锁失败的进队列

class WaitingQueue {
    private volatile int status;
    private static long statusOffset;

    /**
     * 非线程安全,使用时,也要加锁
     */
    private LinkedList<Thread> queue = new LinkedList<>();

    static {
        try {
            statusOffset = UnsafePackage.getUnsafe().objectFieldOffset(WaitingQueue.class.getDeclaredField("status"));
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public void push(Thread thread) {
        while (!comareAndSetStatus(0, 1)) {

        }
        queue.offerLast(thread);
        comareAndSetStatus(1, 0);
        return;
    }

    public Thread pop() {
        while (!comareAndSetStatus(0, 1)) {

        }
        Thread elem = null;
        if (!queue.isEmpty()) {
            elem = queue.pop();
        }
        comareAndSetStatus(1, 0);
        return elem;
    }

    private boolean comareAndSetStatus(int originalStatus, int updateStatus) {
        return UnsafePackage.getUnsafe().compareAndSwapInt(this, statusOffset, originalStatus, updateStatus);
    }
}

 

3.调用如下

public class CustomLockTest {


    private static int count = 0;

    public static void main(String[] args) throws InterruptedException {
        int threadCount = 1500;
        CountDownLatch countDownLatch = new CountDownLatch(threadCount);
        CustomLock lock = new CustomLock();
        long start = System.currentTimeMillis();
        IntStream.range(0, threadCount)
                .forEach(p -> {
                    new Thread() {
                        @Override
                        public void run() {
                            lock.lock();
                            try {
                                for (int i = 0; i < 1000; i++) {
                                    count++;
                                }
                                countDownLatch.countDown();
                            } finally {
                                lock.unlock();
                            }
                        }
                    }.start();
                });

        countDownLatch.await();
        long end = System.currentTimeMillis();
        System.out.println("结果值为:" + count + ",共花费了" + (end - start) + "毫秒!");
    }
}

 

结果值为:1500000,共花费了601毫秒!

 

上一篇:Go语言-输入输出函数


下一篇:Go 学习笔记(74)— Go 标准库之 unsafe