原理: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(); } } }}复制代码
喜欢本文的朋友,欢迎关注,本人的微信公众号,“咖啡牧羊人”