Semaphore是指交通信号灯的意思,常人一般称之为信号灯或者信号量,插播一个题外话,阿里P7的匿名大佬和我说起这个东西的时候一口一个signal,我也没有打脸就手写了signal,然后他说对对对…看来是IDEA滥用综合症吧
Semaphore常用于限制某个资源能被同时访问的线程数量,生活中的一个常见的案例,比如:流水线工作台只有5个坑位,但是工厂HR招人的时候一下子招到了10人,在新的坑位到来之前只能两班倒轮着用而每个奴隶只能占一个工位,而且每个奴隶都有正常生理需求可能要离开工位,此时迅速会有其他奴隶来占据这个坑位保证持续生产,但是坑位一满其他奴隶就不能因为抢工作而出现两人霸占一个坑的情况…
上代码:
package com.unsc.concurrent;
import java.util.concurrent.Semaphore;
/**
* 血汗工厂 一共5个工位
* Created by DELL on 2018/3/15.
*/
public class WorkStation {
/**
* 工位 业务线
*/
static class WorkSite {
private int num;
public WorkSite(int num) {
this.num = num;
}
@Override
public String toString() {
return "WorkSite{" +
"num=" + num +
'}';
}
}
private WorkSite[] workSites = {
new WorkSite(1), new WorkSite(2), new WorkSite(3), new WorkSite(4), new WorkSite(5)};
private boolean[] used = new boolean[5];
private Semaphore semaphore = new Semaphore(5, true);
/**
* 获取一个工位
*/
public WorkSite getWorkSite() throws InterruptedException {
semaphore.acquire(1);
System.out.println("当前可用的工位有" + semaphore.availablePermits() + " 个");
return getNextAvailableWorkSite();
}
/**
* 释放一个工位
*
* @param workSite
*/
public void releaseWorkSite(WorkSite workSite) {
if (makeAsUsed(workSite)) {
semaphore.release(1);
System.out.println("当前可用的工位有" + semaphore.availablePermits() + " 个");
}
}
/**
* 找到一个空闲的工位
*
* @return
` */
private WorkSite getNextAvailableWorkSite() {
for (int i = 0; i < used.length; i++) {
if (!used[i]) {
used[i] = true;
return workSites[i];
}
}
return null;
}
private boolean makeAsUsed(WorkSite workSite) {
for (int i = 0; i < used.length; i++) {
if (workSites[i] == workSite) {
if (used[i]) {
used[i] = false;
return true;
} else {
return false;
}
}
}
return false;
}
}
定义完血汗工厂之后直接开始进行测试
package com.unsc.concurrent;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* Created by DELL on 2018/3/15.
*/
public class SemaphoreDemo {
static class Slave implements Runnable {
private int num;
private WorkStation playground;
public Slave(int num, WorkStation playground) {
this.num = num;
this.playground = playground;
}
@Override
public void run() {
try {
//进入工位
WorkStation.WorkSite workSite = playground.getWorkSite();
if (workSite != null) {
System.out.println("奴隶" + num + "在" + workSite.toString() + "做苦力");
TimeUnit.SECONDS.sleep(2);
System.out.println("奴隶" + num + "离开" + workSite.toString());
//离开工位
playground.releaseWorkSite(workSite);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Executor executor = Executors.newCachedThreadPool();
WorkStation ws= new WorkStation();
for (int i = 0; i < 10; i++) {
executor.execute(new Slave(i+1,ws));
}
}
}
走一遍 结果也是十分明确的
由于Semaphore的存在 不可能出现5个工位6789个人在干活的情况 工位一旦满了 其他奴隶只能被迫等待新的工位释放之后才能进入工位…对于限制某个资源能够同时被访问的线程数Semaphore是有效的…
JDK中的AQS包下 例如CB CDL 信号量等 这些工具都是用来控制并发的,比如信号量的使用场景就是控制某个操作的最大并发数,试想一下一个接口最大支持1000并发,但是实际生产中可能高峰期的时候远大于这个数值,如果说并发请求数量超过这个值有可能会造成宕机,此时使用信号量等并发控制工具就是上策,其他的并发可以在队列中等待或者其他方式来处理,这样做至少可以保证服务的可用不至于挂掉,还是十分有意义的