6 Java多線程:鎖與AQS(下)

您好,我是湘王,這是我的博客園,歡迎您來,歡迎您再來~
之前說過,AQS(抽象隊列同步器)是Java鎖機制的底層實現 。既然它這么優秀,是騾子是馬,就拉出來溜溜吧 。
首先用重入鎖來實現簡單的累加,就像這樣:
【6 Java多線程:鎖與AQS(下)】/** * 用重入鎖實現累加 * * @author 湘王 */public class MyLockTest {private final Lock lock = new ReentrantLock();private int value;public int getNext() {lock.lock();try {value++;} finally {lock.unlock();}return value;}public static void main(String[] args) {MyLockTest myLock = new MyLockTest();for (int i = 0; i < 5; i++) {new Thread(new Runnable() {@Overridepublic void run() {for (int i = 0; i < 5; i++) {System.out.println(myLock.getNext());}}}).start();}}}運行結果顯示數據有重復:

6 Java多線程:鎖與AQS(下)

文章插圖
這么簡單的計算都能出現重復,這肯定是無法接受的 。
再用獨占鎖來試試看:
/** * 利用AQS實現自定義獨占鎖 * * @author 湘王 */public class MyExclusiveLock implements Lock {@Overridepublic void lock() {}@Overridepublic void lockInterruptibly() throws InterruptedException {}@Overridepublic boolean tryLock() {return false;}@Overridepublic boolean tryLock(long time, TimeUnit unit) throws InterruptedException {return false;}@Overridepublic void unlock() {}@Overridepublic Condition newCondition() {return null;}}可以看到,實現lock接口,就需要實現若干自定義的接口 。然后以內部類繼承AQS的方式,實現排他鎖,昨天也說過,AQS中tryAcquire()和tryRelease()是一一對應的,也就是也管獲?。?一個管釋放,所以代碼是:
/** * 內部類繼承AQS的方式,實現排他鎖 */private static class SyncHelper extends AbstractQueuedSynchronizer {private static final long serialVersionUID = -7666580981453962426L;/*** 第一個線程進來,拿到鎖就返回true;后面的線程進來,拿不到鎖就返回false*/@Overrideprotected boolean tryAcquire(int arg) {// 獲取資源狀態int state = getState();if (0 == state) {// 如果沒有線程拿到資源的鎖if (compareAndSetState(0, arg)) {// 保存當前持有同步鎖的線程setExclusiveOwnerThread(Thread.currentThread());return true;}} else if (Thread.currentThread() == getExclusiveOwnerThread()) {// 如果當前線程再次進來 , state + 1,可重入// 如果這里沒有這個判斷,那么程序會卡死setState(state + arg);return true;}return false;}/*** 鎖的獲取和釋放需要一一對應*/@Overrideprotected boolean tryRelease(int arg) {// 獲取資源狀態int state = getState();// 返回最后一個通過setExclusiveOwnerThread()方法設置過的線程 , 或者nullif (Thread.currentThread() != getExclusiveOwnerThread()) {throw new RuntimeException();}setState(state - arg);if (0 == state) {setExclusiveOwnerThread(null);return true;}return false;}protected Condition newCondition() {return new ConditionObject();}}然后再用AQS實現lock接口的方法:
/** * 利用AQS實現自定義獨占鎖 * * @author 湘王 */public class MyExclusiveLock implements Lock {private final SyncHelper synchepler = new SyncHelper();@Overridepublic void lock() {synchepler.acquire(1);}@Overridepublic void lockInterruptibly() throws InterruptedException {synchepler.acquireInterruptibly(1);}@Overridepublic boolean tryLock() {return synchepler.tryAcquire(1);}@Overridepublic boolean tryLock(long time, TimeUnit unit) throws InterruptedException {return synchepler.tryAcquireNanos(1, unit.toNanos(time));}@Overridepublic void unlock() {synchepler.release(1);}@Overridepublic Condition newCondition() {return synchepler.newCondition();}/*** 內部類繼承AQS的方式,實現排他鎖*/private static class SyncHelper extends AbstractQueuedSynchronizer {private static final long serialVersionUID = -7666580981453962426L;/*** 第一個線程進來 , 拿到鎖就返回true;后面的線程進來,拿不到鎖就返回false*/@Overrideprotected boolean tryAcquire(int arg) {// 獲取資源狀態int state = getState();if (0 == state) {// 如果沒有線程拿到資源的鎖if (compareAndSetState(0, arg)) {// 保存當前持有同步鎖的線程setExclusiveOwnerThread(Thread.currentThread());return true;}} else if (Thread.currentThread() == getExclusiveOwnerThread()) {// 如果當前線程再次進來 , state + 1 , 可重入// 如果這里沒有這個判斷 , 那么程序會卡死setState(state + arg);return true;}return false;}/*** 鎖的獲取和釋放需要一一對應*/@Overrideprotected boolean tryRelease(int arg) {// 獲取資源狀態int state = getState();// 返回最后一個通過setExclusiveOwnerThread()方法設置過的線程,或者nullif (Thread.currentThread() != getExclusiveOwnerThread()) {throw new RuntimeException();}setState(state - arg);if (0 == state) {setExclusiveOwnerThread(null);return true;}return false;}protected Condition newCondition() {return new ConditionObject();}}}

推薦閱讀