當面試官問我JDK Semaphore的原理時,我笑了

咖啡牧羊人發表於2019-03-28

原理:Semaphore是用來保護一個或者多個共享資源的訪問,Semaphore內部維護了一個計數器,其值為可以訪問的共享資源的個數。一個執行緒要訪問共享資源,先獲得訊號量,如果訊號量的計數器值大於1,意味著有共享資源可以訪問,則使其計數器值減去1,再訪問共享資源。
如果計數器值為0,執行緒進入休眠。當某個執行緒使用完共享資源後,釋放訊號量,並將訊號量內部的計數器加1,之前進入休眠的執行緒將被喚醒並再次試圖獲得訊號量。
就好比一個廁所管理員,站在門口,只有廁所有空位,就開門允許與空廁數量等量的人進入廁所。多個人進入廁所後,相當於N個人來分配使用N個空位。為避免多個人來同時競爭同一個側衛,在內部仍然使用鎖來控制資源的同步訪問


1、下面,我模仿jdk Semaphore的實現原理,自己實現一遍


package com.jacky;

import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;

/**
 * Created by jacky on 2018/2/13.
 */
public class MySemaphore {

    private Sync sync;

    public MySemaphore(int permits){
       sync = new NonFairSync(permits);
    }

    public MySemaphore(int permits,boolean fair){
        sync = fair ? new FairSync(permits) : new NonFairSync(permits);
    }

    static class Sync extends AbstractQueuedSynchronizer{
        Sync(int permits) {
            setState(permits);
        }

        @Override
        protected boolean tryReleaseShared(int arg) {
            for (;;){
                int oldState = getState();
                int newState = oldState+arg;
                if (compareAndSetState(oldState,newState)){
                    return true;
                }

            }
        }
    }

    static final class FairSync extends Sync{
        FairSync(int permits) {
            super(permits);
        }

        @Override
        protected int tryAcquireShared(int arg) {
            for(;;){
                if (hasQueuedPredecessors()){
                    return -1;
                }
                int oldState = getState();
                int newState = oldState-arg;
                if (newState <0 || compareAndSetState(oldState,newState)){
                    return  newState;
                }
            }
        }
    }

    static final class NonFairSync extends Sync{

        NonFairSync(int permits) {
            super(permits);
        }

        @Override
        protected int tryAcquireShared(int arg) {
            for(;;){
                int oldState = getState();
                int newState = oldState-arg;
                if (newState <0 || compareAndSetState(oldState,newState)){
                    return  newState;
                }
            }
        }
    }

    /**
     * 獲取許可證
     */
    public void acquire(){
        try {
            sync.acquireSharedInterruptibly(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 釋放許可證
     */
    public void release(){
       sync.releaseShared(1);
    }


}
複製程式碼

2、接下來,我們來測試一下

package com.jacky;

import java.util.concurrent.Semaphore;

/**
 * Created by jacky on 2018/2/12.
 */
public class SemaphoreDemo {
    public static void main(String[] args) {
        //Semaphore semaphore = new Semaphore(2, true);
        MySemaphore semaphore = new MySemaphore(2, true);
        Runnable runnable = new Runnable() {

            @Override
            public void run() {
                Thread thread = Thread.currentThread();
                System.out.println("semaphore start:"+thread.getName());
                try {
                    semaphore.acquire();
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                semaphore.release();
                System.out.println("semaphore end:"+thread.getName());

            }
        };

        for (int i=0;i<10;i++){
            Thread thread = new Thread(runnable, "t" + i);
            thread.start();
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
複製程式碼

喜歡本文的朋友,歡迎關注,本人的微信公眾號,“咖啡牧羊人”


相關文章