博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Semaphore信号量真的晦涩难懂?
阅读量:3959 次
发布时间:2019-05-24

本文共 3240 字,大约阅读时间需要 10 分钟。

在介绍Semaphore信号量的时候我们要知道以往学习的synchronized和ReentrantLock锁都是只允许在同一时刻只能有一个线程去访问资源。这与我们生活中的一些情况是不符合的。而Semaphore信号量可以控制多个线程去访问特定的资源。

Semaphore的使用场景:

理解:假设有一个停车场,一次可以停车5辆。而停车管理员就好比我们的Semaphore他可以控制需要停车的车辆。每一个停车位都有一把锁,当来了一辆车后就给该车主一把钥匙,在停车结束后就车主将车钥匙归还给管理员。如果管理员此时已经没有钥匙了就表明停车场没有多余的停车位,那么再来停车的车主则需要等待。

相信这样理解Semaphore就会简单一些。那么我们看一下这个Semaphore是怎么使用的吧

构造方法:Semaphore(int permits) //好比我们停车场的车位数          创建具有给定的许可数和非公平的公平设置的 Semaphore。 Semaphore(int permits, boolean fair)//是否公平表明在等待的时候是否按照车主的先后循序           创建具有给定的许可数和给定的公平设置的 Semaphore。

常用的方法(大白话)

acquire()    从此信号量中获取一个许可证,获取许可证之前处于阻塞状态。可响应中断acquire(int permit)    从此信号量中获取permit个许可证。好比大车需要两个停车位acquireUninterruptibly(int permits)    和上述情况相似,只是不会响应中断标记//带有try的我们可以和ReentrantLock中的tryLock等方法进行比较tryAcquire()     尝试获取许可证,会立即返回。获取返回true反之返回falsetryAcquire(int permit)    尝试获取permit个许可证,也会立即返回tryAcquire(long timeout, TimeUnit unit)    在指定时间内获取许可f证,在指定时间内获取的话返回true,反之返回false    会响应中断release()    释放许可证,就是车主停车结束后需要把锁交给管理员release(int permit)    释放permit个许可证vailablePermits()     当前可用的许可证

代码模拟:一个可以同时停5辆车的停车位一次来了二十辆车。每次停车随机秒

import java.util.Random;import java.util.concurrent.Semaphore;public class SemaphoreTest {
//定义一个方法用来表示停车的随机时间 public static int getTime(){
return new Random().nextInt(3000)+1000; } public static void main(String[] args) {
Semaphore semaphore = new Semaphore(5); //模拟20辆车进行停车 for (int i = 1; i <= 20; i++) {
new ThreadA("车辆"+i,semaphore).start(); } }}class ThreadA extends Thread{
Semaphore semaphore; public ThreadA (String name,Semaphore semaphore){
super(name); this.semaphore = semaphore; } @Override public void run() {
boolean falg = false; try{
//尝试获取许可证,即尝试是否可以停车,不能停车的话处于阻塞状态 semaphore.acquire(); falg = true; System.out.println(Thread.currentThread().getName()+"停车成功"+"==可用停车位为"+semaphore.availablePermits()); Thread.sleep(SemaphoreTest.getTime()); }catch (Exception e){
e.printStackTrace(); }finally {
if(falg){
//停车结束释放许可证 semaphore.release(); System.out.println(Thread.currentThread().getName()+"停车结束"+"==可用停车位为"+semaphore.availablePermits()); } } }}

在这里插入图片描述

在这里插入图片描述

上述结果就是模拟我们平时停车。

代码中值得注意的地方

1.在什么时候释放许可证?

大家可能会说释放许可证肯定是在finally代码块中执行的啊。其实这是很不严谨的,我们知道有可能在获取锁的过程如果出现异常那么将会导致没有获取许可证但是却释放了许可证。将会导致许可证的数量增加。

解决方案就是我们在获取许可证的时候设置一个变量,在finally块中对变量进进行判断是否需要释放许可证。

boolean falg = false;try{
semaphore.acquire(); falg = true;//如果获取许可证成功,那么将会设置变量为true}catch(Exception e){
....}finally{
if(falg){
//只有该变量设置为true,才表明获取了许可证 semaphore.release();//释放许可证}}

2.如果获取许可证后不释放会怎么样

获取许可证后如果不释放将会导致需要许可证(无设置延时策略)的线程阻塞。好比停车后将锁带走将导致后边的车辆不能使用该停车位。

在规定的时间内获取许可证

现实生活中我们去停车时被告知需要等待,当我们得知需要等待的时间过长时我们的一般做法就是换一家停车场。而线程也可以进行此操作

上述代码进行修改:

如果在2秒后获取不到许可证将会选择直接返回

boolean b = semaphore.tryAcquire(2, TimeUnit.SECONDS);            if (!b) {
System.out.println(Thread.currentThread().getName()+"等待时间太久了,更换停车场"); return; }

结果:部分截图

在这里插入图片描述
我们看到有的车辆发现需要等待时间较长时选择了不在这里停车

补充:

1.Semaphore默认是不公平的信号量

公平更接近与现实生活,但是效率很低

2.方法声明InterruptException异常的表明可以响应中断

如果调用线程的interrupt方法时所有声明异常的方法就会抛出异常,并将中断标记清除。

转载地址:http://ejxzi.baihongyu.com/

你可能感兴趣的文章
POJ---1384Piggy-Bank (完全背包+装满问题)
查看>>
并查集基础知识
查看>>
POJ1182---食物链(带权并查集~技巧性超强的解法)
查看>>
POJ2492---A Bug's Life(做完食物链,再秒这个)
查看>>
POJ2063---Investment(完全背包)
查看>>
POJ1458---(最长公共子序列最基础题)
查看>>
POJ3356---(最长公共子序列)
查看>>
二叉树基础知识大全(核心理解遍历)
查看>>
03-树1 树的同构(25 分) 2017秋 数据结构 陈越、何钦铭
查看>>
04-树4 是否同一棵二叉搜索树(25 分)---陈越、何钦铭-数据结构-2017秋
查看>>
表达式求值(C实现,实现多括号,浮点数)---栈的实现以及运用。
查看>>
有序链表的合并(数据结构---单链表)
查看>>
栈实现(数据结构---数组,链表 C实现)
查看>>
POJ3903(dp,最长上升子序列,最基础题)
查看>>
POJ1836-Alignment(最长上升子序列)
查看>>
POJ 1251 Jungle Roads(最小生成树简单题)
查看>>
HDU 1690---Bus System(Floyd模板题+合理定义INF)
查看>>
POJ 2240---Arbitrage(Floyd的dp思想)
查看>>
Dijkstra算法---模板
查看>>
POJ 3680(费用流)
查看>>