线程池的拒绝策略和invokeAll方法的碰撞--来自踩坑记录

本文通过示例分析了线程池在不同拒绝策略下,特别是直接丢弃策略时,如何影响`invokeAll`方法的行为。文章讨论了线程池的工作流程,解释了核心线程数、最大线程数、存活时间等参数的作用,并提醒开发者在使用`invokeAll`时要注意任务执行的条件,建议在必要时采用取消任务的拒绝策略或使用带超时的`invokeAll`方法。
摘要由CSDN通过智能技术生成

一、来由

请看看下述示例,猜猜输出结果:

public class ThreadPoolExample {
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(1),
            new ThreadFactoryBuilder().setNameFormat("task-[%d]").build(), new DiscardPolicy());

        List<Callable<String>> futureTasks = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            futureTasks.add(new MyTask(i));
        }

        try {
            List<Future<String>> futures = executor.invokeAll(futureTasks);

            for (Future<String> future : futures) {
                System.out.println("future.get : " + future.get());
            }
        } catch (InterruptedException e) {
            System.out.println(e);
        } catch (Exception e) {
            System.out.println(e);
        }

    }

    static class MyTask implements Callable<String> {
        private int index;

        public MyTask(int index) {
            this.index = index;
        }

        @Override
        public String call() throws Exception {
            System.out.println(Thread.currentThread().getName() + ": task execute " + index);
            return "task " + index;
        }
    }

    public static class DiscardPolicy implements RejectedExecutionHandler {

        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
            System.out.println(Thread.currentThread().getName() + ": reject task ");
        }
    }

    public static class ThreadFactoryBuilder {
        private String nameFormat = null;

        public ThreadFactoryBuilder setNameFormat(String nameFormat) {
            String.format(nameFormat, 0); // fail fast if the format is bad or null
            this.nameFormat = nameFormat;
            return this;
        }

        public ThreadFactory build() {
            return build(this);
        }

        private static ThreadFactory build(ThreadFactoryBuilder builder) {
            final String nameFormat = builder.nameFormat;
            final ThreadFactory backingThreadFactory = Executors.defaultThreadFactory();
            final AtomicLong count = (nameFormat != null) ? new AtomicLong(0) : null;
            return runnable -> {
                Thread thread = backingThreadFactory.newThread(runnable);
                if (nameFormat != null) {
                    thread.setName(String.format(nameFormat, count.getAndIncrement()));
                }
                thread.setDaemon(false);
                return thread;
            };
        }
    }
}

猜猜看上面的程序将输出什么?
如果将拒绝策略改为ThreadPoolExecutor.CallerRunsPolicy呢?

  1. 使用直接丢弃策略的输出值为:
task-[0]: task execute 0
task-[0]: task execute 1
main: reject task 
main: reject task 
task-[0]: task execute 3
  1. 使用ThreadPoolExecutor.CallerRunsPolicy拒绝策略的输出值为:
main: task execute 2
task-[0]: task execute 0
task-[0]: task execute 1
main: task execute 4
task-[0]: task execute 3
future.get : task 0
future.get : task 1
future.get : task 2
future.get : task 3
future.get : task 4

分析上述两个结果发现,当直接把FutureTask任务丢弃后,future.get便不再输出,仅仅拒绝策略的不同,结果却大相径庭,这是为何呢?

让我们接着往下看

二、线程池简介

首先,让我们来看看ThreadPoolExecutor所为何物。

这是ThreadPoolExecutor的构造方法

 public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)
  • corePoolSize:核心线程数
  • maximumPoolSize:最大线程数
  • keepAliveTime:线程存活时间
  • unit:线程存活时间的单位
  • workQueue:工作队列
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值