aqs初步理解

2018-06-16  本文已影响10人  兴浩

1.介绍

AQS,AbstractQueuedSynchronizer,即队列同步器。它是构建锁或者其他同步组件的基础框架(如ReentrantLock、ReentrantReadWriteLock、Semaphore等),JUC并发包的作者(Doug Lea)期望它能够成为实现大部分同步需求的基础。它是JUC并发包中的核心基础组件。

2.state状态

AQS使用一个int类型的成员变量state来表示同步状态,当state>0时表示已经获取了锁,当state = 0时表示释放了锁。它提供了三个方法(getState()、setState(int newState)、compareAndSetState(int expect,int update))来对同步状态state进行操作,当然AQS可以确保对state的操作是安全的。

    private volatile int state;

    protected final int getState() {
        return state;
    }

    protected final void setState(int newState) {
        state = newState;
    }

    protected final boolean compareAndSetState(int expect, int update) {
        // See below for intrinsics setup to support this
        return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
    }

代码示例:

        public void stateTest() {
            int state = getState();
            System.out.println("state:" + state);
            setState(1);
            state = getState();
            System.out.println("state:" + state);
            boolean bFlag = this.compareAndSetState(1, 2);
            state = getState();
            System.out.println("state:" + state);
        }

输出结果

state:0
state:1
state:2

3.tryAcquire和tryRelease

2个方法需要重写,即对state状态维护的策略,如下示例代码,实现独占锁机制

    public static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860L;

        @Override
        protected final boolean tryAcquire(int acquires) {
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        @Override
        protected final boolean tryRelease(int releases) {
            if (getState() == 0) {
                throw new IllegalMonitorStateException();
            }
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }
}

测试代码:

        public void tryAcquireTest() {
            boolean bFlag=tryAcquire(1);
            if(bFlag)
            {
                try {
                    System.out.println("working");
                    TimeUnit.SECONDS.sleep(5);
                    System.out.println("worked");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                tryRelease(1);
            }
        }

    @Test
    public void test2()
    {
        Sync sync=new Sync();
        sync.tryAcquireTest();
    }

4.acquire和release

tryAcquire如果在多线程环境情况下调用,只会在tryAcquire返回true时才执行,返回false则不执行代码,这不符合代码逻辑

测试代码:

    @Test
    public void test3() throws InterruptedException {
        Sync sync=new Sync();

        Thread thread1=new Thread(new Runnable() {
            @Override
            public void run() {
                sync.tryAcquireTest();
            }
        });
        Thread thread2=new Thread(new Runnable() {
            @Override
            public void run() {
                sync.tryAcquireTest();
            }
        });

        thread1.start();
        thread2.start();

        thread1.join();
        thread2.join();
    }

结果输出:

working
worked

可以使用acquire和release方法来实现以上逻辑

        public void acquireTest() {
            acquire(1);
            try {
                System.out.println("working");
                TimeUnit.SECONDS.sleep(2);
                System.out.println("worked");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            release(1);
        }

输出结果:

working
worked
working
worked

5.FIFO队列

acquire实现了一个模板方法,当tryAcquire返回false,则将当前线程添加到一个队列中,这个点是理解的关键点

    public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

参考:

【死磕Java并发】—–J.U.C之AQS:AQS简介

上一篇下一篇

猜你喜欢

热点阅读