Java ThreadPoolExecutor 能同时运行的最大线程数问题

关于线程池参数的解释:

image.png
我这样设置,同时运行的线程数为什么大于maximumPoolSize,不应该只有一个线程同时运行吗?

        THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(
                1,
                1,
                60,
                TimeUnit.MILLISECONDS,
                new LinkedBlockingDeque<>(1),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.CallerRunsPolicy());

执行方法:

private static void testThreadPoolExecutor() {
        THREAD_POOL_EXECUTOR.execute(() -> {
            System.out.println("线程1");
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        THREAD_POOL_EXECUTOR.submit(() -> {
            System.out.println("线程2");
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        THREAD_POOL_EXECUTOR.execute(() -> {
            System.out.println("线程3");
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        THREAD_POOL_EXECUTOR.execute(() -> {
            System.out.println("线程4");
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        THREAD_POOL_EXECUTOR.execute(() -> {
            System.out.println("线程5");
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        THREAD_POOL_EXECUTOR.shutdown();
    }

结果,同时运行了两个线程(总是比maximumPoolSize大1),为什么不是一个
image.png

阅读 3k
3 个回答

首先,看一下你这个五个线程$n,实际上称之为任务更合适。

  1. 线程1直接创建一个线程来执行
  2. 线程2进入队列

这两个是没有问题的。

然后,看线程3,这个时候,线程数队列都达到最大了,使用reject策略。
CallerRunsPolicy:

public static class CallerRunsPolicy implements RejectedExecutionHandler {
       
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                r.run();
            }
        }
    }

直接在当前线程执行run方法。
这里又多了一个线程,就是执行这段代码的线程,可能就是你的主线程

这就是为什么有两个线程的原因。

后续的线程4线程5会在线程池线程当前线程这两个线程中运行 。

如果你使用了AbortPolicy策略,在线程3时,就直接报异常了:

public static class AbortPolicy implements RejectedExecutionHandler {
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            throw new RejectedExecutionException("Task " + r.toString() +
                                                 " rejected from " +
                                                 e.toString());
        }
    }

同样的,由于线程1要执行3秒,后续的线程4线程5都会直接抛出异常。当然,你要处理这个异常,要不然,程序就中断了。
线程1执行结束,执行队列中的线程2

因为你用的是 CallerRunsPolicy ,就是线程池不够的时候用掉用方的线程执行
改成 AbortPolicy 就会拒绝执行了

你的饱和策略,如果不够执行,就会交由主线程完成。多线程的情况下,通知运行的线程至少都有2个吧,一个主线程,一个执行线程。这没什么奇怪你,你设置的是线程池,不包含主线程。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题