美文网首页
aqs初步理解

aqs初步理解

作者: 兴浩 | 来源:发表于2018-06-16 21:10 被阅读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简介

    相关文章

      网友评论

          本文标题:aqs初步理解

          本文链接:https://www.haomeiwen.com/subject/eggleftx.html