手写AQS同步器

1,535 阅读3分钟

一、什么是AQS?

AQS是AbstractQueuedSynchronizer抽象队列同步器的简称,是实现同步器的基础组件,JDK并发包JUC下面Lock的实现以及一些并发工具类就是通过AQS来实现的。

二、AQS主要用来解决什么问题?

AQS主要是用来解决高并发情况下的线程同步问题,是Synchronized内置锁的一种替代方案。

三、本文目的

通过剖析AQS原理,实现一个自定义的同步锁。

四、案例场景

秒杀场景:共有库存5件,多个线程进行消费,需要保证不产生超卖现象,如果消费成功,提示购买成功,当前剩余库存件数,如果库存消费完,提示购买失败,库存为0。

五、代码实现

5.1 准备工作

数据库脚本

create table shop_order
(
    id    int auto_increment primary key,
    stock int null;
);

准备一条数据

insert into shop_order(id,stock) values(1,5);

这里需要介绍一个IDE的代码生成利器EasyCode,可以根据表结构快速的生成基本的增删改查代码,具体的用法这里不再赘述,网上有非常的教程讲解。

5.2 Synchronized实现
public synchronized String decStockNoLock() {
        Integer stock;
        ShopOrder shopOrder = this.shopOrderDao.queryById(1);
        stock = shopOrder.getStock();
        if (shopOrder.getStock() <= 0) {
            log.info("下单失败,已经没有库存了");
            return "下单失败,已经没有库存了";
        }
        stock--;
        shopOrder.setStock(stock);
        int update = this.shopOrderDao.update(shopOrder);
        if (update > 0) {
            log.info("下单成功,当前剩余产品数--->" + stock);
            return "下单成功,当前剩余产品数--->" + stock;
        }
        return "系统出现异常";
    }
5.3 自定义AQS锁实现

本节将在上节代码的基础上,不采用synchronized关键字,而使用自定义AQS锁的方法来解决并发问题,同时达到深入理解AQS原理的目的。

/**
 * 自定义AQS锁,解决并发竞争问题
 *
 * @author Administrator
 */
@Component
public class SelfLock {
    /**
     * 当前加锁状态,记录加锁的次数
     */
    private volatile int state = 0;

    /**
     * 当前持有锁的线程
     */
    private Thread lockHolder;

    /**
     * 等待队列
     */
    private ConcurrentLinkedQueue<Thread> waiters = new ConcurrentLinkedQueue();

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
    }

    public Thread getLockHolder() {
        return lockHolder;
    }

    public void setLockHolder(Thread lockHolder) {
        this.lockHolder = lockHolder;
    }

    /**
     * 获取锁
     */
    public boolean acquire() {
        // cas比较与交换,原子算法
        Thread current = Thread.currentThread();
        // 初始状态
        int c = getState();
        if (c == 0) { //如果C=0,表明同步器还没有被持有
            // 获取锁需要判断队列里面是否为空或者队列里面的第一个对象是本身可以持有锁
            if ((waiters.size() == 0 || current == waiters.peek()) && compareAndSwapState(0, 1)) {
                setLockHolder(current);
                return true;
            }
        }
        return false;
    }

    /**
     * 加锁
     */
    public void lock() {
        //获取锁
        if (acquire()) {
            return;
        }
        //如果没有获取到锁,那么这里需要处理线程阻塞,等待
        // cas比较与交换,原子算法
        Thread current = Thread.currentThread();
        //将线程对象加入等待队列
        waiters.add(current);
        // 自旋 需要考虑性能问题 避免CPU超载
        for (; ; ) {
            if (current == waiters.peek() && acquire()) {
                waiters.poll(); // 将队列第一个线程对象弹出
                return;
            }
            // 阻塞当前线程
            LockSupport.park(current);
        }
    }

    /**
     * 解锁
     */
    public void unlock() {
        //判断持有锁对象是否为当前线程
        if (Thread.currentThread() != lockHolder) {
            throw new RuntimeException("Current Thread is not lockholder!");
        }
        int state = getState();
        //如果持有锁对象为当前线程,需要初始化state和lockholder的值
        if (compareAndSwapState(state, 0)) {
            setLockHolder(null);
            Thread first = waiters.peek();
            //判断等待队列是否为空,如果不为空,则唤醒队列peek的值
            if (first != null) {
                LockSupport.unpark(first);
            }
        }
    }

    /**
     * 原子修改状态,unsafe类只能通过反射来进行操作
     */
    public final boolean compareAndSwapState(int except, int update) {
        return unsafe.compareAndSwapInt(this, stateOffset, except, update);
    }

    private static final Unsafe unsafe = UnsafeInstance.reflectGetUnsafe();

    private static final long stateOffset;

    static {
        try {
            stateOffset = unsafe.objectFieldOffset(SelfLock.class.getDeclaredField("state"));
        } catch (Exception e) {
            throw new Error();
        }
    }
}

使用自定义AQS锁

/**
     * 减库存
     */
    @Override
    public String decStockNoLock() {
        selfLock.lock();
        Integer stock;
        ShopOrder shopOrder = this.shopOrderDao.queryById(1);
        stock = shopOrder.getStock();
        if (shopOrder.getStock() <= 0) {
            log.info("下单失败,已经没有库存了");
            selfLock.unlock();
            return "下单失败,已经没有库存了";
        }
        stock--;
        shopOrder.setStock(stock);
        int update = this.shopOrderDao.update(shopOrder);
        if (update > 0) {
            log.info("下单成功,当前剩余产品数--->" + stock);
            selfLock.unlock();
            return "下单成功,当前剩余产品数--->" + stock;
        }
        return "系统出现异常";
    }