synchronized和重入锁ReentrantLock,这2种锁一次都只能允许一个线程访问一个资源,而信号量可以控制有多少个线程可以访问特定的资源
Semaphore常用场景:限流
看过一个大佬写过的例子:
比如有个停车场,有5个空位,门口有个门卫,手中5把钥匙分别对应5个车位上面的锁,来一辆车,门卫会给司机一把钥匙,然后进去找到对应的车位停下来,出去的时候司机将钥匙归还给门卫。停车场生意比较好,同时来了100两车,门卫手中只有5把钥匙,同时只能放5辆车进入,其他车只能等待,等有人将钥匙归还给门卫之后,才能让其他车辆进入。
上面的例子中门卫就相当于Semaphore,车钥匙就相当于许可证,车就相当于线程。
Semaphore主要方法
Semaphore(int permits):构造方法,参数表示许可证数量,用来创建信号量
Semaphore(int permits,boolean fair):构造方法,当fair等于true时,创建具有给定许可数的计数信号量并设置为公平信号量
void acquire() throws InterruptedException:从此信号量获取1个许可前线程将一直阻塞,相当于一辆车占了一个车位,此方法会响应线程中断,表示调用线程的interrupt方法,会使该方法抛出InterruptedException异常
void acquire(int permits) throws InterruptedException :和acquire()方法类似,参数表示需要获取许可的数量;比如一个大卡车要入停车场,由于车比较大,需要申请3个车位才可以停放
void acquireUninterruptibly(int permits) :和acquire(int permits) 方法类似,只是不会响应线程中断
boolean tryAcquire():尝试获取1个许可,不管是否能够获取成功,都立即返回,true表示获取成功,false表示获取失败
boolean tryAcquire(int permits):和tryAcquire(),表示尝试获取permits个许可
boolean tryAcquire(long timeout, TimeUnit unit) throws InterruptedException:尝试在指定的时间内获取1个许可,获取成功返回true,指定的时间过后还是无法获取许可,返回false
boolean tryAcquire(int permits, long timeout, TimeUnit unit) throws InterruptedException:和tryAcquire(long timeout, TimeUnit unit)类似,多了一个permits参数,表示尝试获取permits个许可
void release():释放一个许可,将其返回给信号量,相当于车从停车场出去时将钥匙归还给门卫
void release(int n):释放n个许可
int availablePermits():当前可用的许可数
举例,设置许可数为2.打印线程获取许可过程
acquire()
package com.example.demo.demo.conditionLockDemo;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
/**
* SemaPhore信息量:常用场景:限流
*synchronized和重入锁ReentrantLock,这2种锁一次都只能允许一个线程访问一个资源,而信号量可以控制有多少个线程可以访问特定的资源。
*/
public class SemaPhoreDemo {
static Semaphore semaphore = new Semaphore(2);//参数表示许可证数量,用来创建信号量
public static class T extends Thread{
@Override
public void run() {
try {
semaphore.acquire();//获取许可
System.out.println(System.currentTimeMillis()+":"+Thread.currentThread().getName()+"获取许可");
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
finally {
semaphore.release();
System.out.println(System.currentTimeMillis()+":"+Thread.currentThread().getName()+"释放许可");
}
}
}
public static void main(String[] args) {
for (int i = 0; i <10 ; i++) {
T t = new T();
t.setName("t"+i);
t.start();
}
}
}
结果
1590980975333:t0获取许可
1590980975333:t1获取许可
1590980977334:t1释放许可
1590980977334:t2获取许可
1590980977334:t0释放许可
1590980977334:t3获取许可
1590980979334:t3释放许可
1590980979334:t2释放许可
1590980979334:t5获取许可
1590980979334:t4获取许可
1590980981334:t4释放许可
1590980981334:t6获取许可
1590980981334:t7获取许可
1590980981334:t5释放许可
1590980983335:t6释放许可
1590980983335:t8获取许可
1590980983335:t9获取许可
1590980983335:t7释放许可
1590980985335:t9释放许可
1590980985335:t8释放许可
结果t0和t1获取到许可,2秒后t1释放许可,t2才能获取到,只要当存在可用许可数时,线程才能获取并访问
规定的时间内希望获取许可
package com.example.demo.demo.conditionLockDemo;
import java.sql.Time;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
/**
* Semaphore中定时获取许可
*/
public class SemaphoreDemo2 {
static Semaphore semaphore = new Semaphore(1);
public static class T extends Thread{
@Override
public void run() {
Boolean acquireSuccess = false;//获取许可是否成功
try {
//1秒尝试获取许可,获取成功返回true,失败false
System.out.println(System.currentTimeMillis()+":"+Thread.currentThread().getName()+"尝试获取许可,当前可用许可数量"+semaphore.availablePermits());
acquireSuccess = semaphore.tryAcquire(1, TimeUnit.SECONDS);
if(acquireSuccess){
System.out.println(System.currentTimeMillis()+":"+Thread.currentThread().getName()+"成功获取许可,当前可用许可数量"+semaphore.availablePermits());
TimeUnit.SECONDS.sleep(5);
}else {
System.out.println(System.currentTimeMillis()+":"+Thread.currentThread().getName()+"获取许可失败,当前可用许可数量"+semaphore.availablePermits());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
finally {
if (acquireSuccess){
semaphore.release();
System.out.println(System.currentTimeMillis()+":"+Thread.currentThread().getName()+"成功释放许可,当前可用许可数量"+semaphore.availablePermits());
}
}
}
public static void main(String[] args) throws InterruptedException {
T t1 = new T();
t1.setName("t1");
T t2 = new T();
t2.setName("t2");
T t3 = new T();
t3.setName("t3");
t1.start();
TimeUnit.SECONDS.sleep(1);
t2.start();
TimeUnit.SECONDS.sleep(1);
t3.start();
}
}
}
1590981406919:t1尝试获取许可,当前可用许可数量1
1590981406921:t1成功获取许可,当前可用许可数量0
1590981407918:t2尝试获取许可,当前可用许可数量0
1590981408919:t2获取许可失败,当前可用许可数量0
1590981408919:t3尝试获取许可,当前可用许可数量0
1590981409921:t3获取许可失败,当前可用许可数量0
1590981411921:t1成功释放许可,当前可用许可数量1