自定义实现ReentrantLock

关于线程的CAS操作,借助了JDK中的 sun.misc.Unsafe类,该类如果直接调用,会抛出安全异常。这里使用反射技术创建sun.misc.Unsafe类的对象。

使用JDK中的ConcurrentLinkedQueue作为队列。

可重入的功能暂时未实现。

代码如下:

import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.locks.LockSupport;

public class MyReentrantLock {
    //锁状态,默认为0,表示无锁。获取锁则加1,释放锁则建1。
    private volatile int state;
    //持有锁的线程
    private Thread lockHolder;
    //创建一个线程安全的同步队列,存放等待获取锁的线程
    private ConcurrentLinkedQueue queue=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 tryAcquire() {
        Thread  thread=Thread.currentThread();
        int state=getState();
        if(state==0){
            //如果是公平锁,获取锁的时候需要判断当前线程是否是同步队列中第一个排队的,非公平锁不用判断队列
           if((queue.size()==0||thread==queue.peek())&&compareAndSwapState(0,1)){
               setLockHolder(thread);
               return true;
           }
        }
        return false;
    }

    /**
     * 获取锁,三种场景
     * 1,使用CAS直接获取锁
     * 2,如果没有获取锁则停留在当前方法
     * 3,其他线程将锁释放后,该线程尝试再次获取锁
     */
    public void lock(){
        //使用CAS获取锁
        if(tryAcquire()){
            return;
        }
        // 没有获取到锁的线程,将其引用放到队列中
        Thread  currentThread=Thread.currentThread();
        queue.add(currentThread);

        //阻塞等待,死循环会特别占用CPU,因此使用LockSupport.park阻塞线程。阻塞的线程需要唤醒后才能继续执行
        for(;;){
            //如果线程被唤醒,继续尝试获取锁
            if((queue.size()==0||currentThread==queue.peek())&&tryAcquire()){
                //System.out.println(currentThread.getName()+"获取到了锁");
                //同步队列中获取到锁线程,需要从同步队列中取出
                queue.poll();
                return;
            }
            //阻塞线程,如果没有获取锁则停留在当前方法
            LockSupport.park(currentThread);
        }
    }
    //释放锁
    public void unlock(){
        Thread  currentThread=Thread.currentThread();
        if(currentThread!=getLockHolder()){
            throw  new RuntimeException("不是持有锁的线程,不能释放");
        }

        //释放锁,将锁状态置为0
        int state=getState();
        if(compareAndSwapState(state,0)){
           // System.out.println(currentThread.getName()+"释放了锁");
            //当前获取锁的线程置null,没有线程获取到锁
            setLockHolder(null);
            //从队列中获得第一个等待的线程,并将其唤醒
            Thread thread = queue.peek();
            LockSupport.unpark(thread);

        }
    }

    /**
     * 使用CAS设置锁状态,该操作是原子操作
     * @param oldValue
     * @param newValue
     * @return
     */
    private boolean compareAndSwapState(int oldValue,int newValue){
        return unsafe.compareAndSwapInt(this,stateOffset,oldValue,newValue);
    }

    /**
     * 使用反射获取Unsafe实例,无法直接获取,否则会报安全异常
     * @return
     */
    static Unsafe getUnsafeInstance(){
        Field field = null;
        try {
            field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            return (Unsafe)field.get(null);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;

    }


    private static final Unsafe unsafe = getUnsafeInstance();
    private static final long stateOffset;

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

}

 

测试代码:

public class LockTest {
    //商品数量
    private  int stockCount=5;
    //自定义锁
    MyReentrantLock reentrantLock=new MyReentrantLock();

    public static void main(String[] args) {
        LockTest lockTest = new LockTest();
        ExecutorService executorService = Executors.newFixedThreadPool(10);

        for(int i=0;i<10;i++){
            executorService.execute(
                    new Runnable() {
                        @Override
                        public void run() {
                            lockTest.descStock();
                        }
                    }
            );
        }

        executorService.shutdown();

    }

    //模拟数据库减库存
    void descStock(){
        //Runtime
        Thread currentThread = Thread.currentThread();
        String threadName = currentThread.getName();
        reentrantLock.lock();
        if(stockCount>0){
            //模拟数据库延时,方便看到效果
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            stockCount--;
            System.out.println(threadName+"下单成功,商品剩余" + stockCount);
        }else{
            System.out.println(threadName+"下单失败,已经没有商品剩余" );
        }
        reentrantLock.unlock();

    }
}

 

测试代码输出:

pool-1-thread-2下单成功,商品剩余4
pool-1-thread-4下单成功,商品剩余3
pool-1-thread-6下单成功,商品剩余2
pool-1-thread-8下单成功,商品剩余1
pool-1-thread-10下单成功,商品剩余0
pool-1-thread-1下单失败,已经没有商品剩余
pool-1-thread-3下单失败,已经没有商品剩余
pool-1-thread-5下单失败,已经没有商品剩余
pool-1-thread-7下单失败,已经没有商品剩余
pool-1-thread-9下单失败,已经没有商品剩余

 

你可能感兴趣的:(其他,并发编程,多线程,java)