`

并发编程回顾:信号量Semaphore

 
阅读更多

原先多线程并发编程的学习笔记和代码整理一下贴上来。

---------------------------------

信号量Semaphore

根据JDK文档描述:

一个计数信号量。从概念上讲,信号量维护了一个许可集。如有必要,在许可可用前会阻塞每一个 acquire(),然后再获取该许可。每个 release() 添加一个许可,从而可能释放一个正在阻塞的获取者。但是,不使用实际的许可对象,Semaphore 只对可用许可的号码进行计数,并采取相应的行动。

个人理解为定义一个信号量同时指定它的许可数量,acquire时许可+1,release时许可-1。如果到达最大许可数时,后面的线程会阻塞。

一个简单的示例:

定义一个打印资源id的任务。该任务在运行前先获取信号量的一个许可,运行完后会释放该许可。

class ResourceInfo implements Runnable{
	private final int resId;
	private Semaphore semaphore;
	public ResourceInfo(int rid,Semaphore semp){
		this.semaphore=semp;
		resId=rid;
	}
	@Override
	public void run() {
		try{
			semaphore.acquire();
			System.out.println("resId:"+resId);
			Thread.sleep((long) (Math.random() * 10000));  
			semaphore.release();
		}catch(InterruptedException e){
			e.printStackTrace();
		}
	}
}
然后使用信号量:
ExecutorService exec = Executors.newCachedThreadPool();
Semaphore semap=new Semaphore(10);
for(int i=0;i<20;i++){
	exec.execute(new ResourceInfo(i, semap));
}
exec.shutdown();

这里定义了一个信号量,最多允许10个任务获取许可,然后一次启动20个任务。运行结果如下:

resId:0
resId:2
resId:1
resId:3
resId:5
resId:6
resId:4
resId:7
resId:8
resId:9
resId:10
resId:11
resId:13
resId:12
resId:14
resId:16
resId:15
resId:17
resId:19
resId:18

前10个任务获取到许可后,后面的10个任务会阻塞,直到前面的任务释放许可。这里我们修改一下:

Semaphore semap=new Semaphore(10,true);

指定公平设置(默认为false):如果此信号量保证在争用时按先进先出的顺序授予许可,则为 true;否则为 false。再运行一下看看:

resId:0
resId:3
resId:2
resId:1
resId:4
resId:5
resId:7
resId:6
resId:8
resId:9
resId:10
resId:11
resId:12
resId:13
resId:14
resId:15
resId:16
resId:17
resId:18
resId:19

公平设置后,被阻塞的线程就会按照先进先出的顺序获得许可,因此,后面10个线程是顺序打印Id信息的。

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics