使用AQS自定义重入锁

一、创建MyLock

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

public class MyLock implements Lock {

    private Helper helper = new Helper();

    @Override
    public void lock() {
        helper.acquire(1);
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {
        helper.acquireInterruptibly(1);
    }

    @Override
    public boolean tryLock() {
        return helper.tryAcquire(1);
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        return helper.tryAcquireNanos(1, unit.toNanos(time));
    }

    @Override
    public void unlock() {
        helper.release(1);
    }

    @Override
    public Condition newCondition() {
        return helper.newCondition();
    }

    private class Helper extends AbstractQueuedSynchronizer { 
        @Override
        protected boolean tryAcquire(int arg) {
            //如果第一个线程进来,可以拿到锁,返回true

            //如果第二个线程进来,拿不到锁,返回false,有种特例,如果当前进来的线程和当前保存的线程是同一个线程,则可以拿到锁,但是要更新状态值

            //如何判断是第一个线程进来还是其他线程进来

            int state = getState();
            Thread t = Thread.currentThread();

            if (state == 0) {//判断是否是第一个线程
                if (compareAndSetState(0, arg)) {
                    setExclusiveOwnerThread(Thread.currentThread());
                    return true;
                }
            } else if(getExclusiveOwnerThread() == t) {//判断当前进来的线程和当前保存的线程是否是同一个线程,实现重入锁,因为锁的是对象,所以只要是同一个Helper对象线程就是同一个线程
                setState(state + 1);
                return true;
            }
            return false;
        }

        @Override
        protected boolean tryRelease(int arg) {
            //锁的获取和释放肯是一一对应的,那么调用此方法的线程一定是当前线程
            if (Thread.currentThread() != getExclusiveOwnerThread()) {
                throw new RuntimeException();
            }

            int state = getState() - arg;
            setState(state);

            if (state == 0) {
                setExclusiveOwnerThread(null);
                return true;
            }
            return false;
        }

        protected ConditionObject newCondition() {
            return new ConditionObject();
        }

    }
}

 

二、编写测试代码

public class TestMyLock {

    private int value;
    private MyLock myLock = new MyLock();

    public int getValue() {
        myLock.lock();
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        value ++;
        myLock.unlock();
        return value;
    }

    public void a() {
        myLock.lock();
        System.out.println("a");
        b();
        myLock.unlock();
    }

    public void b() {
        myLock.lock();
        System.out.println("b");
        myLock.unlock();
    }

    public static void main(String[] args) {
        TestMyLock testMyLock = new TestMyLock();

        //检测是否会并发
        Runnable runnable = () -> {
          for (int i = 0; i<100; i++) {
              System.out.println(Thread.currentThread().getId()+",值:" + testMyLock.getValue());
          }
        };

        new Thread(runnable).start();
        new Thread(runnable).start();
        new Thread(runnable).start();
        
        //检测重入锁
        Runnable runnable1 = () -> testMyLock.a();
        new Thread(runnable1).start();
    }
}

 

posted @ 2019-05-22 11:51  谋知  阅读(326)  评论(0编辑  收藏  举报