AQS 核心原理实现(独占锁)

AQS ( AbstractQueuedSynchronizer) 抽象队列同步器 

通过源码我们可以看到其实AQS是使用了CAS,保证原子性。

那么CAS到底是什么呢?

CAS:Compare and Swap,即比较再交换。

CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。 如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值 。否则,处理器不做任何操作。无论哪种情况,它都会在 CAS 指令之前返回该 位置的值。

 所有CAS其实是操作内存,但是java是不能直接操作内存区域,所有又有了一个类叫Unsafe,java的Unsafe类为我们提供了类似C++可以操作内存。

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() {
    }
    ...
}

所以我们无法通过new 的方式来实例化,那么我们要如何实例化这个类?

其实我们java也可以通过反射来实例化对象,现在我们利用反正来实例化unsafe

package com.gpdi.dispatch.config;

import sun.misc.Unsafe;

import java.lang.reflect.Field;

/**
 * @Author Lxq
 * @Date 2020/3/8 15:42
 * @Version 1.0
 */
public class UnsafeInstance {

    public static Unsafe reflectGetUnsafe() {
        try {
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            return (Unsafe) field.get(null);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }
}

那么我们接下来就实现一个独占锁

package com.gpdi.dispatch.config;

import sun.misc.Lock;
import sun.misc.Unsafe;

import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.locks.LockSupport;

/**
 * @Author Lxq
 * @Date 2020/3/8 15:27
 * @Version 1.0
 */
public class AQSLock {

    /**
     * 当前加锁的状态
     */
    private volatile int state = 0;

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

    private static ConcurrentLinkedDeque<Thread> waiters = new ConcurrentLinkedDeque<>();

    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;
    }

    /**
     * 加锁
     *
     * @return
     */
    public Boolean aquire() {
        // cas比较交换-原子算法
        Thread current = Thread.currentThread();
        // 初始状态
        int c = getState();
        if (c == 0) {
            // 同步器还没有被持有
            if ((waiters.size() == 0 || current == waiters.peek()) && compareAndSwapStatu(0, 1)) {
                setLockHolder(current);
                //加锁成功,直接返回
                return true;
            }
        }
        return false;
    }

    public void lock() {
        if (aquire()) {
            // 加锁成功
            return;
        }
        Thread current = Thread.currentThread();
        // 将加锁不成功的线程放入队列中
        waiters.add(current);
        // 自旋
        for (; ; ) {
            if ((current == waiters.peek()) && aquire()) {
                waiters.poll();
                return;
            }
            // 阻塞当前线程
            LockSupport.park(current);
        }

    }

    public void unLock() {
        // 当前线程是否是锁持有的线程
        if (Thread.currentThread() != lockHolder) {
            throw new RuntimeException("lockholder is not current thread");
        }
        int state = getState();
        if (compareAndSwapStatu(state, 0)) {
            setLockHolder(null);
            // 唤醒队列中线程
            Thread first = waiters.peek();
            if (first != null) {
                LockSupport.unpark(first);
            }

        }

    }

    /**
     * 原子操作
     *
     * @param except
     * @param update
     * @return
     */
    private final Boolean compareAndSwapStatu(int except, int update) {
        return unsafe.compareAndSwapInt(this, stateOffset, except, update);
    }

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

    private static long stateOffset;

    static {
        try {
            stateOffset = unsafe.objectFieldOffset(AQSLock.class.getDeclaredField("state"));
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }

}

创建一个测试,压测一下

package com.gpdi.dispatch.service;

import com.gpdi.dispatch.config.AQSLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Author Lxq
 * @Date 2020/3/8 16:29
 * @Version 1.0
 */
@Service
public class TradeService {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    private static AQSLock aqs = new AQSLock();

    private static Lock lock  = new ReentrantLock();

    public String descStockNoLock() {
        aqs.lock();
        Integer stock;
        List<Map<String, Object>> result = jdbcTemplate
                .queryForList("select * from shop_order where id = 1");

        if (result == null || result.isEmpty() || (stock = (Integer) result.get(0).get("stock")) <= 0) {
            System.out.println("下单失败,已经没有库存了");
            aqs.unLock();
            return "下单失败,已经没有库存了";
        }
        stock--;
        jdbcTemplate.update("update shop_order set stock = ? where id = 1",stock);
        System.out.println("下单成功,当前剩余------》" + stock);
        aqs.unLock();
        return "下单成功,当前剩余-----》" + stock;
    }
}

创建压测接口

package com.gpdi.dispatch.controller;

import com.gpdi.dispatch.service.TradeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Author Lxq
 * @Date 2020/3/8 16:34
 * @Version 1.0
 */
@RestController
@RequestMapping("/aqs")
public class AQSTestController {


    @Autowired
    private TradeService tradeService;

    @RequestMapping("/stock")
    public void testAqs(){
        tradeService.descStockNoLock();
    }
}

利用Jmeter,压测

发布了90 篇原创文章 · 获赞 29 · 访问量 7257

猜你喜欢

转载自blog.csdn.net/weixin_38982591/article/details/104742612
今日推荐