Java多线程技术之Semaphore(信号量)

Semaphore的作用:

在java中,使用了synchronized关键字和Lock锁实现了资源的并发访问控制,在同一时间只允许唯一了线程进入临界区访问资源(读锁除外),这样子控制的主要目的是为了解决多个线程并发同一资源造成的数据不一致的问题。在另外一种场景下,一个资源有多个副本可供同时使用,比如打印机房有多个打印机、厕所有多个坑可供同时使用,这种情况下,Java提供了另外的并发访问控制--资源的多副本的并发访问控制,今天学习的信号量Semaphore即是其中的一种。


package com.np.ota.test.semaphore;

import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 打印室
 * Semaphore:信号量,允许指定最多几个线程访问某个资源,
 * 例如一个打印室里面有3台打印机可以同时打印,那么打印队列可以同时有三个任务在打印
 * @author luke
 */
public class PrintRoom {

	private final Semaphore semaphore;
	
	/**多台打印机*/
	private boolean[] freePrinters;
	
	private Lock lockPrinters;

	public PrintRoom(int limitSize) {
		semaphore = new Semaphore(limitSize,true);
		freePrinters = new boolean[limitSize];
		for(int i = 0; i < limitSize; i++){
			freePrinters[i] = true;
		}
		lockPrinters = new ReentrantLock();
	}
	
	public void printJob(Object document){
		try {
			semaphore.acquire();
			int assignedPrinter = getPrinter();
			//这里存在多线程访问(个数为信号量限制大小),所以启动各自线程执行
			new Thread(new DoJob(semaphore,freePrinters, assignedPrinter)).start();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		/*finally{
			semaphore.release();
		}*/
	}
	
	/**
	 * 获取空闲打印机,这里要用锁控制并发访问(并发数量是信号量大小)
	 * @return
	 */
	private int getPrinter(){
		lockPrinters.lock();
		int ret = -1;
		try {
			for(int i = 0; i < freePrinters.length; i++){
				if(freePrinters[i]){
					ret = i;
					freePrinters[i] = false;
					break;
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			lockPrinters.unlock();
		}
		return ret;
	}
	
	class DoJob implements Runnable {
		
		private Semaphore semaphore;
		
		private boolean[] freePrinterss;
		
		private int assigned;
		
		public DoJob(Semaphore semaphore,boolean[] freePrinters, int assignedPrinter) {
			this.semaphore = semaphore;
			this.freePrinterss = freePrinters;
			this.assigned = assignedPrinter;
		}

		@Override
		public void run() {
			try {
				//执行打印任务
				long duration = (long)(Math.random()*10+1);
				System.out.println(Thread.currentThread().getName()+",用打印机:"+assigned+",需要花时长:"+duration);
				Thread.sleep(duration);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}finally{
				//打印任务结束,允许新的打印任务进入打印室
				freePrinterss[assigned] = true;
				semaphore.release();
			}
		}
		
	}
	
}
package com.np.ota.test.semaphore;

/**
 * 模拟一个线程任务,执行打印
 * @author luke
 */
public class Job implements Runnable{
	
	private PrintRoom printQueue;

	public Job(PrintRoom printQueue) {
		this.printQueue = printQueue;
	}

	@Override
	public void run() {
		printQueue.printJob(new Object());
	}

}


package com.np.ota.test.semaphore;

public class Main {

	public static void main(String[] args) {

		//打印室,有3台打印机
		int limitSize = 3;
		PrintRoom printRoom = new PrintRoom(limitSize);
		
		//一百个打印任务
		Thread[] threads = new Thread[100];
		for(int i =0; i < 100; i++){
			threads[i] = new Thread(new Job(printRoom),"Thread"+i);
		}
		for(int i =0; i < 100; i++){
			threads[i].start();
		}
		
	}

}
 

结果:

Thread-0,用打印机:0,需要花时常:7
Thread-1,用打印机:1,需要花时常:2
Thread-2,用打印机:2,需要花时常:5
Thread-3,用打印机:1,需要花时常:7
Thread-4,用打印机:2,需要花时常:4
Thread-5,用打印机:0,需要花时常:6
Thread-6,用打印机:2,需要花时常:10
Thread-7,用打印机:1,需要花时常:5
Thread-8,用打印机:0,需要花时常:8
Thread-9,用打印机:1,需要花时常:6
Thread-10,用打印机:2,需要花时常:8
Thread-11,用打印机:0,需要花时常:9
Thread-12,用打印机:1,需要花时常:7
Thread-13,用打印机:2,需要花时常:7
Thread-15,用打印机:1,需要花时常:2
Thread-14,用打印机:0,需要花时常:5
Thread-16,用打印机:1,需要花时常:1
Thread-17,用打印机:1,需要花时常:7
Thread-19,用打印机:2,需要花时常:7
Thread-18,用打印机:0,需要花时常:7
Thread-20,用打印机:1,需要花时常:4

Thread-21,用打印机:0,需要花时常:3

。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值