关于老师举例线程池+Semaphore配合使用的问题

来源:10-5 Semaphore用法和注意点

正义柔情永在

2020-03-01

老师,虽然直接上代码,但是很简单就10行左右,我的疑问在注释中

public class SemaphoreTest {
public static void main(String[] args) {

    Random random = new Random(System.currentTimeMillis());

    //凭证管理器,最多允许2个线程同时获取到凭证
    Semaphore semaphore  = new Semaphore(2);

    //创建大小为5的线程池,并且缓存队列容量为0
    ThreadPoolExecutor executors = new ThreadPoolExecutor(
            5,
            5,
            0L, TimeUnit.MILLISECONDS,
            new SynchronousQueue<>(),
            new ThreadPoolExecutor.AbortPolicy());

    //提交6个任务
    for (int i = 0; i < 6; i++) {
        try {
            executors.submit(()->{
                try {
                    /**
                     * 此处会阻塞,也就是限制了后续业务访问能力,通过串行方式运行。
                     * 但是无法限制提交任务,如果要限制提交,则将拒绝策略换成{@link ThreadPoolExecutor.CallerRunsPolicy}
                     * 那么任务就会阻塞在提交线程中执行,从而限制了提交能力。
                     *
                     * TODO 我的问题是:如果一开始就只允许2个线程并发访问后续业务方法,为什么一开始不直接创建2个大小的线程池就行了,而是
                     * TODO 创建一个更大的线程池,而又在任务内部进行阻塞呢?
                     */
                    semaphore.acquire();
                    Thread.sleep(random.nextInt(1000));
                    System.out.println(Thread.currentThread().getName()+"执行完毕。");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }finally {
                    semaphore.release();
                }
            });
        }catch (Exception e){
            System.err.println(e.getMessage()); //Rejected 提交速度超出线程池能力,采用AbortPolicy 抛出异常
        }
    }

    executors.shutdown();
}

}

写回答

1回答

悟空

2020-03-01

这是一个非常好的问题。让我们举一个在实际业务中会遇到的例子。比如我们在调用该“慢服务”前,需要有判断条件,比如我们只想在每天的0点整才会去访问这个“慢服务”,假设这个“慢服务”是“检查今天是否是星期日”。那么在大部分情况下(除了每天的0点),我们想要有更多的并发线程来提高性能,所以线程池的数量应该设置得大一些,而不仅仅是3个线程。此时我们就可以利用Semaphore来达到这个目的。

类似地,在大型应用程序中,会有不同类型的任务,通过不同的线程池来调用我们的“慢服务”,我们的调用方不仅仅是一个人,或者调用我们的直接是Tomcat服务器或者网关,我们就更不能限制,也不应该限制调用方的线程数量。

而一旦我们使用了Semaphore,由于信号量具有跨线程(跨线程池)的特性,那么即使这些请求来自于不同的线程池,我们也可以限制它们的访问。

基于以上的理由,如果想限制并发访问的线程数,用并发原语Semaphore是更合适的。


3
0

深度解密Java并发工具,精通JUC,成为并发多面手

JUC全方位讲解,构建并发工具类知识体系

1599 学习 · 573 问题

查看课程