天天看点

并发编程 AbstractQueuedSynchronizer 类实战之独占式可重入实现(十六)

今天分享并发编程 AbstractQueuedSynchronizer 类实战使用之独占式和可重入实现:

一、独占式锁的实现:

1、核心代码:

//实现lock接口
public class SelfLock implements Lock {
    // 静态内部类,自定义同步器
    private static class Sync extends AbstractQueuedSynchronizer {


        /*判断处于占用状态*/
        @Override
        protected boolean isHeldExclusively() {
            return getState()==1;
        }

        /*获得锁 重写父类AbstractQueuedSynchronizer中的方法*/
        @Override
        protected boolean tryAcquire(int arg) {
            if(compareAndSetState(0,1)){
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        /*释放锁 重写父类AbstractQueuedSynchronizer中的方法*/
        @Override
        protected boolean tryRelease(int arg) {
            if(getState()==0){
                throw new IllegalMonitorStateException();
            }
            setExclusiveOwnerThread(null);
            setState(0);
            //compareAndSetState(1,0);
            return true;
        }

        // 返回一个Condition,每个condition都包含了一个condition队列
        Condition newCondition() {
            return new ConditionObject();
        }
    }

    // 仅需要将操作代理到Sync上即可
    private final Sync sync = new Sync();

    public void lock() {
    	System.out.println(Thread.currentThread().getName()+" ready get lock");
        sync.acquire(1);//去父类 AbstractQueuedSynchronizer 调用此方法
        System.out.println(Thread.currentThread().getName()+" already got lock");
    }

    public boolean tryLock() {
        return sync.tryAcquire(1);
    }

    public void unlock() {
    	System.out.println(Thread.currentThread().getName()+" ready release lock");
        sync.release(1);//去父类 AbstractQueuedSynchronizer 调用此方法
        System.out.println(Thread.currentThread().getName()+" already released lock");
    }

    public Condition newCondition() {
        return sync.newCondition();
    }

    public boolean isLocked() {
        return sync.isHeldExclusively();
    }

    public boolean hasQueuedThreads() {
        return sync.hasQueuedThreads();
    }

    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

    public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }
}
           

2、main方法多线程测试:

public class TestMyLock {

    public void test() {
        final Lock lock = new SelfLock();
        class Worker extends Thread {

			public void run() {
                lock.lock();
                System.out.println(Thread.currentThread().getName());
                try {
                    SleepTools.second(1);
                } finally {
                    lock.unlock();
                }
            }
        }
        // 启动4个子线程
        for (int i = 0; i < 4; i++) {
            Worker w = new Worker();
            //w.setDaemon(true);
            w.start();
        }
        // 主线程每隔1秒换行
        for (int i = 0; i < 10; i++) {
        	SleepTools.second(1);
            //System.out.println();
        }
    }

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

3、测试结果:

并发编程 AbstractQueuedSynchronizer 类实战之独占式可重入实现(十六)

很明显的就会发现锁的获取和释放的规律。 但是这是一个不可重入的独占式锁的实现,即如果循环重复调用,会出现死锁。怎样让其可重入呢?只需修改加锁和释放锁的方法即可。

二、可重入锁:

1、获取锁核心代码:

public boolean tryAcquire(int acquires) {
            // 当状态为0的时候获取锁
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            // 当状态不为0的时候获取锁,即可重入获取锁
            }else if(getExclusiveOwnerThread()==Thread.currentThread()){
                setState(getState()+1);
                return  true;
            }
            return false;
        }
           

2、释放锁核心代码:

protected boolean tryRelease(int releases) {
            if(getExclusiveOwnerThread()!=Thread.currentThread()){
                throw new IllegalMonitorStateException();
            }
            if (getState() == 0)
                throw new IllegalMonitorStateException();

            setState(getState()-1);//可能多次取到锁,每次释放减一
            if(getState()==0){// 最后一次释放锁,将状态设置为0
                setExclusiveOwnerThread(null);
            }
            return true;
        }
           

后续看ReentrantLock源码就会发现,其实现原理都是类似的,不谋而合。

继续阅读