Semaphore源码阅读

140 阅读1分钟

Semaphore简介

		
	public class SemaphoreDemo {

		public static void main(String[] args) {

			//第二个参数可以配置是否是公平信号量
			final Semaphore semaphore = new Semaphore(3, true);

			new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						semaphore.acquire();
						Thread.sleep(200);
						System.out.println(Thread.currentThread().getId() + "已运行");
					} catch (InterruptedException e) {
						e.printStackTrace();
					} finally {
						semaphore.release();
					}
				}
			}).start();

			new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						semaphore.acquire(3);
						Thread.sleep(200);
						System.out.println(Thread.currentThread().getId() + "已运行");
					} catch (InterruptedException e) {
						e.printStackTrace();
					} finally {
						semaphore.release(3);
					}
				}
			}).start();

			new Thread(new Runnable() {
				@Override
				public void run() {
					try {
						semaphore.acquire(2);
						Thread.sleep(200);
						System.out.println(Thread.currentThread().getId() + "已运行");
					} catch (InterruptedException e) {
						e.printStackTrace();
					} finally {
						semaphore.release(2);
					}
				}
			}).start();
		}
	}
	

  • Semaphore:信号量,继承AQS使用其共享模式,初始化其state值,表示资源值

  • acquire(n):将state值减n,成功即获取资源

  • release(n):将state值加n,成功即释放资源

以公平信号量为例解析acquire()流程

  • 公平信号量和非公平信号量不同:非公平信号量会直接尝试获取资源,而公平信号量会查看阻塞队列是否有线程等待

  • 公平信号量和非公平信号量相同:release()相同

		
	public void acquire() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }
	
	//AQS中的acquireSharedInterruptibly()
	public final void acquireSharedInterruptibly(int arg) throws InterruptedException {
		
		if (Thread.interrupted())
			throw new InterruptedException();

		//Semaphore重写了此方法,以公平信号量为例,下面具体会写
		if (tryAcquireShared(arg) < 0)
			
			//将线程加入阻塞队列等待,具体见AQS源码阅读(三)
			doAcquireSharedInterruptibly(arg);
	}
	
	//返回的remaining小于0:获取资源失败
	protected int tryAcquireShared(int acquires) {
		for (;;) {
			
			//阻塞队列内是否有线程等待:具体见AQS源码阅读(一)
			if (hasQueuedPredecessors())
				return -1;
			
			//情况一:阻塞队列内没有线程等待
			//情况一:当前结点是阻塞队列的后继结点

			//AQS中的state值
			int available = getState();
			
			//remaining:信号量剩余值
			int remaining = available - acquires;

			//remaining < 0:信号量资源值不足,获取失败
			//compareAndSetState():CAS操作设置state值
			if (remaining < 0 || compareAndSetState(available, remaining))
				return remaining;
		}
	}
	

解析release()流程

		
	public void release() {
        sync.releaseShared(1);
    }
	
	//AQS的releaseShared()
	public final boolean releaseShared(int arg) {
		
		//Semaphore重写了此方法,下面具体会写
		if (tryReleaseShared(arg)) {
			
			//唤醒阻塞队列中的线程,具体见AQS源码阅读(三)
			doReleaseShared();
			return true;
		}
		return false;
	}
	
	//自旋释放资源
	protected final boolean tryReleaseShared(int releases) {
		for (;;) {
			
			////AQS中的state值
			int current = getState();
			
			//释放资源之后的state值
			int next = current + releases;
			
			//溢出
			if (next < current) // overflow
				throw new Error("Maximum permit count exceeded");
			
			//CAS设置state值
			if (compareAndSetState(current, next))
				return true;
		}
	}