天天看点

一、Java多线程并发同步之Semaphore

概念

Semaphore是一种在多线程环境下使用的设施,该设施负责协调各个线程,用来

管理资源

,以保证它们能够正确、合理的使用公共资源的设施,也是操作系统中用于控制进程同步互斥的量。用我们常见的说法就是用来

控制并发

数。

信号量是一个非负整数 。

业务场景

以售票窗口买票为例,假设火车站有两个售票窗口,一开始两个窗口都是没有人的,这是同时来了10个人买票,每次只允许2个人同时买票,每个窗口前一个人买完后面的人接着买,而其他人就排队等待前面的人买完离开,如此往复。

上述场景中10个人就是10个线程,2个窗口就是资源,信号量就是控制2个窗口,

当开始售票时,有2个人能获取允许进入窗口买票,其信号量就会减2,剩下的人就进入等待状态,当其中一个人完成买票,就会释放一个窗口,信号量就会加1,马上会有另外一个人获取允许进入窗口,信号量就减1,如此一次循环下去,直到所有人买完票,释放所有窗口。

实现

Semaphore(int permits):构造方法,创建具有给定许可数的计数信号量并设置为非公平信号量。

Semaphore(int permits,boolean fair):构造方法,当fair等于true时,创建具有给定许可数的计数信号量并设置为公平信号量(FIFO)。

void acquire():获取资源

void acquire():释放资源

public class SemaphoreTest {
	/**
	 * 执行任务 操作信号量
	 *
	 */
	class BuyRunnable implements Runnable {
		private Semaphore semaphore;
		private int user;
		
		public BuyRunnable(Semaphore semaphore,int user){
			this.semaphore = semaphore;
			this.user = user;
		}

		@Override
		public void run() {
			try {
				semaphore.acquire(); // 获取信息量许可(可以买票)
				System.out.println("user" + user + "---进入窗口,准备开始买票");
				// 模拟买票,每个人使用窗口买票的时间不定
				Thread.sleep((long)(Math.random()*10000));
				System.out.println("user" + user + "---买票完成,准备离开窗口");
				Thread.sleep((long)(Math.random()*10000));
				System.out.println("user" + user + "---离开窗口");
				
				semaphore.release(); // 释放许可(窗口空了)
				System.out.println("当前可使用的许可数为:"+semaphore.availablePermits());
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

	}

	public static void main(String[] args) {
		SemaphoreTest semaphoreTest = new SemaphoreTest();
		ExecutorService pool = Executors.newCachedThreadPool();
		final Semaphore semaohore = new Semaphore(2); // 定义两个窗口
		
		//10个用户买票
		for (int i = 0; i < 10; i++) {
			pool.execute(semaphoreTest.new BuyRunnable(semaohore,(i+1)));
		}
		pool.shutdown();
	}
}
           

输出结果:

user1---进入窗口,准备开始买票
user4---进入窗口,准备开始买票
user4---买票完成,准备离开窗口
user1---买票完成,准备离开窗口
user1---离开窗口
当前可使用的许可数为:1
user5---进入窗口,准备开始买票
user4---离开窗口
user8---进入窗口,准备开始买票
当前可使用的许可数为:0
user5---买票完成,准备离开窗口
user5---离开窗口
user9---进入窗口,准备开始买票
当前可使用的许可数为:0
user8---买票完成,准备离开窗口
user9---买票完成,准备离开窗口
user9---离开窗口
user2---进入窗口,准备开始买票
当前可使用的许可数为:0
user8---离开窗口
当前可使用的许可数为:1
user3---进入窗口,准备开始买票
user2---买票完成,准备离开窗口
user3---买票完成,准备离开窗口
user2---离开窗口
user6---进入窗口,准备开始买票
当前可使用的许可数为:0
user3---离开窗口
user7---进入窗口,准备开始买票
当前可使用的许可数为:0
user6---买票完成,准备离开窗口
user7---买票完成,准备离开窗口
user6---离开窗口
当前可使用的许可数为:1
user10---进入窗口,准备开始买票
user7---离开窗口
当前可使用的许可数为:1
user10---买票完成,准备离开窗口
user10---离开窗口
当前可使用的许可数为:2

           

结论

使用Semaphore信息量主要就是控制线程并发数,诸如上述业务场景其实还有很多,例如停车场车位,排队上厕所等等,都可以通过Semaphore来控制。

继续阅读