Java架构师交流群:793825326
java版本:jdk1.8
IDE:Idea2019
Semaphore属于Java并发库里面的类,它在我看来算是线程池的一种吧,当然它和真正的线程池还是有些差别的。它的原理是管理一定数量的许可证,当线程要运行的时候,首先从它这里获取许可证(acquire),如果它的许可证发放完了,那么这个线程就要等待,直到其他的线程释放了许可证(release)。参考如下的示例代码:
private static final Semaphore semaphore=new Semaphore(2);
public static void main(String[] args) {
Thread thread1=new Thread(new Runnable() {
@Override
public void run() {
try {
semaphore.acquire();
System.out.println("thread1 start");
for (int i = 0; i < 10; i++) {
Thread.sleep(500);
System.out.println("thread1 is working");
}
System.out.println("thread1 end");
semaphore.release();
} catch (Exception ex) {
System.out.println(ex.toString());
}
}
});
Thread thread2=new Thread(new Runnable() {
@Override
public void run() {
try {
semaphore.acquire();
System.out.println("thread2 start");
for (int i = 0; i < 5; i++) {
Thread.sleep(500);
System.out.println("thread2 is working");
}
System.out.println("thread2 end");
semaphore.release();
} catch (Exception ex) {
System.out.println(ex.toString());
}
}
});
Thread thread3=new Thread(new Runnable() {
@Override
public void run() {
try {
semaphore.acquire();
System.out.println("thread3 start");
System.out.println("thread3 end");
semaphore.release();
} catch (Exception ex) {
System.out.println(ex.toString());
}
}
});
try {
thread1.start();
thread2.start();
thread3.start();
}
catch (Exception ex) {
System.out.println(ex.toString());
}
}
这段代码的执行结果为:
thread1 start
thread2 start
thread1 is working
thread2 is working
thread1 is working
thread2 is working
thread2 is working
thread1 is working
thread1 is working
thread2 is working
thread2 is working
thread2 end
thread1 is working
thread3 start
thread3 end
thread1 is working
thread1 is working
thread1 is working
thread1 is working
thread1 is working
thread1 end
thread3尝试获取许可证失败,因为许可证只有两个,只能等待,直到thread2释放了许可证,thread3才往下执行。
下面简单说一下信号量和线程池的区别。
它们之间的区别有两点:
1)线程池是会开启新线程,而信号量不开启新线程,信号量所谓的新线程是使用者自己开启的。
2)线程池等到线程结束后会自动释放许可,信号量的许可不管是获取还是释放,都需要手动操作。
这就决定了它俩的使用场景上的不同,线程池的使用场景,不用多说,就是管理线程,避免线程滥用。信号量的使用场景,我认为更多的是避免一些代码同时运行太多,比如有个方法,可能会在很多线程里面使用,但是我们又不想让这个方法在太多线程里面同时调用,因为可能会耗费大量的系统资源,这个时候,你就可以增加一个全局的信号量,让这个方法在执行前获取许可,执行结束后释放许可,这样就避免了太多地方同时执行这个方法。在高并发的应用场景中,我们可能经常会有限流的操作,就是让接口同时接受的请求数量有一个上限,达到上限,其他的就要等待,这里就可以用信号量来解决。还有,假如有两个方法A和B,我们不希望这两个方法同时被执行,在同一时间,只允许一个方法被执行,那么我们仍然可以用信号量来解决。