Semaphore(信号量),是一种共享锁,多个线程同时访问一个资源时,通过它实现同一时刻的访问线程数量。位于java.util.concurrent.Semaphore,最常见的使用场景就是高并发下的限流。
举个例子:有10000辆车同时要涌入高速公路,但高速入口没有ETC只有2条人工发卡车道,所有人都必须要被收费亭许可(收费亭确认放行)后才能进入高速。高速公路是大家要共同使用的资源,收费亭就是Semaphore,2个发卡通道是Semaphore的同时允许车辆通过的许可证数量
使用代码示例:
public class TestCar {
//收费站同时容纳的车辆2
private static Semaphore semaphore=new Semaphore(2);
public static void main(String[] args) {
//模拟100辆车进入停车场
for(int i=0; i<10000; i++){
Thread thread=new Thread(new Runnable() {
public void run() {
try {
System.out.println("===="+Thread.currentThread().getName()+"来到收费站");
if(semaphore.availablePermits()==0) {
System.out.println("工作人员正为其他车辆发卡,请耐心等待");
}
semaphore.acquire();//获取令牌尝试进入收费亭
System.out.println(Thread.currentThread().getName()+"成功进入收费亭");
//.....
//模拟车辆在收费亭停留时间
System.out.println(Thread.currentThread().getName()+"驶入高速公路");
semaphore.release();//释放令牌,腾出车位,处理下一台车
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, i + "号车");
thread.start();
}
}
}
其他用法:利用new Semaphore(0) 进行初始化控制,初始化完成后通过Semaphore.release释放锁,继续执行其他代码。以场景说明:外卖快递员收到推送过来的订单,进行订单信息梳理确认,开始派送订单到客户手上
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 收到订单
String orderData = "你收到新的外卖订单,订单详情....";
// 处理订单
Postman.getInstance().onReceiveOrder(orderData);
}
}
/**
* 注意:实现了Runnable接口
*/
public class Postman implements Runnable {
private static Postman mInstance;
private Semaphore semaphore = new Semaphore(0);
// 初始化
public static Postman getInstance() {
if (null == mInstance) {
synchronized (Postman.class) {
if (null == mInstance) {
mInstance = new Postman();
}
}
}
return mInstance;
}
public void onReceiveOrder(String data) {
System.out.println("处理订单数据,确认收货人姓名、地址等,代码略……");
// 这句代码,会释放锁进入run()方法,触发开始派送流程
semaphore.release();
}
// 开启一个后台线程,执行派送订单操作
public Postman() {
new Thread(this).start();
}
@Override
public void run() {
// 循环检查订单,如果有订单进行派送
while (true) {
if (semaphore.tryAcquire()) { // 因为许可证数量是0,这里会一直阻塞,直到释放锁(semaphore.release) 才会执行下面代码
System.out.println("收到订单,开始派送,代码自行扩展....");
} else {
try {
Thread.sleep(1000);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}
}
从上面代码可以看出:在订单处理没有完成之前,semaphore会一直等待release通知,阻塞派单流程的代码,知道release释放锁后,才会往下执行。