并发编程:线程同步工具:1、Semaphore 使用信号量控制对资源的N个副本的并发访问

目录

Semaphore:

主程序:

打印机组:

执行结果:


Semaphore:

这是一个计数器,用来控制N个共享资源的访问,这是一种基本的并发编程工具。(主要针对单个锁只能由一个线程进行执行,而升级的可以由N个线程同时执行的一种并发控制。)

 

主程序:

该DEMO模拟20个任务,共享3个打印机的过程。并使其有序使用打印机。(每个时刻都会有3个线程在执行打印任务)

package xyz.jangle.thread.test.n3_2.semaphore;

/**
 * Semaphore DEMO 使用信号量控制对资源的N个副本的并发访问
 * 	该DEMO模拟20个任务,共享3个打印机的过程。并使其有序使用打印机。
 * 
 * 	Semaphore的功能类型的同步锁的机制,但其区别是,其并发执行的数量并不限制为1个线程。
 * 	由 new Semaphore(3)参数3进行设置同步数量。
 * 	由 semaphore.acquire()来进行获取,acquire(2)可获取2个信号量。
 * 	由 semaphore.release()来进行释放,release(2)可释放2个信号量。
 * 
 * 
 * @author jangle
 * @email jangle@jangle.xyz
 * @time 2020年8月8日 下午4:47:53
 * 
 */
public class M {

	public static void main(String[] args) {

		PrintQueue printQueue = new PrintQueue();
		for (int i = 0; i < 20; i++) {
			createThread(printQueue, i).start();
		}

	}

	/**
	 * 创建线程
	 * 
	 * @author jangle
	 * @time 2020年8月8日 下午5:21:23
	 * @param printQueue
	 * @return
	 */
	private static Thread createThread(PrintQueue printQueue, int i) {
		return new Thread(() -> {
			System.out.println(Thread.currentThread().getName() + "开始执行");
			printQueue.printJob(new Object());
			System.out.println(Thread.currentThread().getName() + "完成执行");
		}, "Thread" + i);
	}

}

打印机组:

模拟3台打印机,对外提供服务。(方法可支持3个线程同时执行)

package xyz.jangle.thread.test.n3_2.semaphore;

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

/**
 * 	模拟3台打印机进行对外服务
 * @author jangle
 * @email jangle@jangle.xyz
 * @time 2020年8月8日 下午4:52:28
 * 
 */
public class PrintQueue {

	// 信号量控制
	private final Semaphore semaphore;
	// 打印机组
	private final boolean freePrintes[];
	// 对获取打印机时,进行同步控制。
	private final Lock lockPrinters;

	public PrintQueue() {
		super();
		this.semaphore = new Semaphore(3);
		this.freePrintes = new boolean[3];
		for (int i = 0; i < freePrintes.length; i++) {
			freePrintes[i] = true;
		}
		this.lockPrinters = new ReentrantLock();
	}

	/**
	 * 主要功能,使用信号量对现有打印机资源进行控制
	 * 
	 * @author jangle
	 * @time 2020年8月8日 下午4:57:30
	 * @param document
	 */
	public void printJob(Object document) {
		try {
			// 获取访问许可(信号量)
			semaphore.acquire();
			int assignedPrinter = getPrinter();
			System.out.println("模拟打印... 打印机编号" + assignedPrinter + "。当前线程" + Thread.currentThread().getName());
			TimeUnit.SECONDS.sleep((long) (Math.random() * 10));
			freePrintes[assignedPrinter] = true;
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			// 释放许可(信号量)
			semaphore.release();
		}
	}

	/**
	 * 	获取打印机
	 * 
	 * @author jangle
	 * @time 2020年8月8日 下午5:18:20
	 * @return
	 */
	private int getPrinter() {
		// 用于保存打印机编号
		int ret = -1;
		try {
			lockPrinters.lock();
			for (int i = 0; i < freePrintes.length; i++) {
				if (freePrintes[i]) {
					ret = i;
					freePrintes[i] = false;
					break;
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			lockPrinters.unlock();
		}
		return ret;
	}
}

执行结果:

Thread2开始执行
Thread5开始执行
Thread4开始执行
模拟打印... 打印机编号0。当前线程Thread2
模拟打印... 打印机编号2。当前线程Thread4
Thread3开始执行
Thread12开始执行
Thread0开始执行
Thread1开始执行
Thread13开始执行
Thread8开始执行
Thread7开始执行
Thread9开始执行
Thread10开始执行
模拟打印... 打印机编号1。当前线程Thread5
Thread6开始执行
Thread14开始执行
Thread16开始执行
Thread17开始执行
Thread19开始执行
Thread18开始执行
Thread15开始执行
Thread11开始执行
Thread5完成执行
模拟打印... 打印机编号1。当前线程Thread3
Thread3完成执行
模拟打印... 打印机编号1。当前线程Thread0
Thread2完成执行
模拟打印... 打印机编号0。当前线程Thread12
Thread0完成执行
模拟打印... 打印机编号1。当前线程Thread1
Thread4完成执行
模拟打印... 打印机编号2。当前线程Thread13
Thread12完成执行
模拟打印... 打印机编号0。当前线程Thread8
Thread13完成执行
模拟打印... 打印机编号2。当前线程Thread7
Thread7完成执行
模拟打印... 打印机编号2。当前线程Thread9
Thread1完成执行
模拟打印... 打印机编号1。当前线程Thread10
Thread8完成执行
模拟打印... 打印机编号0。当前线程Thread6
Thread10完成执行
模拟打印... 打印机编号1。当前线程Thread14
Thread6完成执行
模拟打印... 打印机编号0。当前线程Thread16
Thread14完成执行
模拟打印... 打印机编号1。当前线程Thread17
Thread9完成执行
模拟打印... 打印机编号2。当前线程Thread19
Thread17完成执行
模拟打印... 打印机编号1。当前线程Thread18
Thread16完成执行
模拟打印... 打印机编号0。当前线程Thread15
Thread19完成执行
模拟打印... 打印机编号2。当前线程Thread11
Thread18完成执行
Thread11完成执行
Thread15完成执行

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值