併發----AQS

1 瞭解AQS

要求:可以畫出AQS自旋鎖的圖且複述出整個過程java

AQS (AbstractQueuedSynchronizer)是一個幫助器,自定義鎖的一個幫助器(體如今代碼上 私有的內部類繼承AQS)api

2 瞭解AQS的API

要求:經過java.util.concurrent.locks 下的 Lock和 AbstractQueuedSynchronizer的api瞭解AQS安全

Acquire()ide

嘗試獲取鎖,若是沒有獲取到鎖的畫,就把當前節點放置到隊列的末尾測試

3 可以經過AQS寫一個鎖

自定義鎖ui

package src.main.concurrent.AQS;

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

/**
 * 自定義鎖
 * 1 實現Lock
 * 2 AQS 私有內部類繼承AQS
 * 3 重寫tryAcquire/tryRelease
 * compareAndSetState   經過CAS方式修改值
 * setExclusiveOwnerThread  設置當前值佔有資源
 *
 * 可重入鎖,在MyLock基礎之上修改  獲取鎖 釋放鎖部分邏輯
 *
 * @author liuhuxiang
 * @version $Id: MyLock.java, v 0.1 2018年10月09日 21:18 liuhuxiang Exp $
 */
public class MyLock implements Lock {

    private AQSHelper aQSHelper = new AQSHelper();

    // 這裏就能夠體現AQS是一個幫助類
    private class AQSHelper extends AbstractQueuedSynchronizer {

        //獲取鎖
        //注意這裏的arg表示信號量,正常來講arg爲1
        @Override
        protected boolean tryAcquire(int arg) {

            //當前資源沒有線程佔用
            if (getState() == 0) {
                //經過CAS方式獲取原子性的修改
                if (compareAndSetState(0, arg)) {
                    //設置當前值佔有資源
                    setExclusiveOwnerThread(Thread.currentThread());
                    return true;
                }
          //可重入鎖--獲取鎖修改 只要在AQS基礎之上加上一個判斷便可 }else if(getExclusiveOwnerThread()==Thread.currentThread()){ setState(getState()+arg); return true; }
            return false;
        }

        //釋放鎖
        @Override
        protected boolean tryRelease(int arg) {
            //減去信號量
            int state = getState() - arg;
            boolean flag = false;
            //判斷釋放後是否爲0
            if (state == 0) {
                setExclusiveOwnerThread(null);
                setState(state);
                return true;
            }
            //存在線程安全嗎?重入性的問題,當前已經獨佔了資源()state,因此這裏不存在安全問題
           //可重入鎖--釋放鎖修改 這裏不要作任何修改,等於獲取鎖加了兩邊arg,釋放鎖減掉兩邊arg
            setState(state);
            return false;
        }

        //這裏參考jdk
        public Condition newConditionObject() {
            return new ConditionObject();
        }

    }

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

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

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

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        //試圖以獨佔模式獲取對象,若是被中斷則停止,若是到了給定超時時間,則會失敗。

        return aQSHelper.tryAcquireNanos(1, unit.toNanos(time));
    }

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

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

使用自定義鎖spa

package src.main.concurrent.AQS;

/**
 * 測試MyLock
 * 建立20個線程,每一個線程調用++方法,驗證加鎖不加鎖兩種方式
 *
 * @author liuhuxiang
 * @version $Id: TestMyLock.java, v 0.1 2018年10月09日 21:37 liuhuxiang Exp $
 */
public class TestMyLock {

    private int m = 0;

    MyLock myLock = new MyLock();

    private int increase() {
        myLock.lock();
        try {
            return m++;
        } finally {
            //確保最終釋放鎖
            myLock.unlock();
        }
    }

    public static void main(String[] args) {
        TestMyLock testMyLock = new TestMyLock();
        Thread[] threads = new Thread[20];
        for (int i = 0; i < 20; i++) {
            threads[i] = new Thread(() -> {
                System.out.println(testMyLock.increase());
            });
            threads[i].start();
        }

    }

}

探討可重入鎖線程

package src.main.concurrent.AQS;

/**
 * 探討重入性問題
 * 調用的時候,發現只打印了a ,爲何只打印了a,由於a()方法佔用了鎖,資源不爲0了,因此b沒法暫用資源
 *
 * 因此要去修改MyLock,多加一個可重入性的判斷
 *
 * 可重入性:同一個鎖多同一資源進行佔有的時候,直接分配給這個線程
 *
 * @author liuhuxiang
 * @version $Id: TestMyLock2.java, v 0.1 2018年10月09日 21:46 liuhuxiang Exp $
 */
public class TestMyLock2 {

    private int m = 0;

    MyLock myLock = new MyLock();

    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) {
        TestMyLock2 testMyLock2 = new TestMyLock2();

        new Thread(() -> {
            testMyLock2.a();
        }).start();

    }

}
相關文章
相關標籤/搜索