Java-线程池

一、线程池3种常用方式

ExecutorService poolExecutor = Executors.newCachedThreadPool();
Executors.newFixedThreadPool(5);
Executors.newCachedThreadPool();

但是阿里巴巴的java开发手册规定,不允许手动创建线程,必须使用线程池;同时线程池不能用Executors来获取,必须通过ThreadPoolExecutor

二、线程池7大参数

点进上面这几个创建线程池的方法中可以发现,其背后都是创建了一个名叫ThreadPoolExecutor的对象,该对象的创建依赖7个参数。

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)
  • corePoolSize:指定线程池的核心线程数。
  • maximumPoolSize:指定线程池的最大线程数。与核心线程数的区别就是核心线程数是一直活跃的,最大线程数包括核心线程数和一部分不活跃的线程。当核心线程和队列都占用的情况下就会新开线程【不会超过最大线程】处理请求;请求处理完成后,这些超过核心线程的新启动的线程就会在超过最大空闲时间被释放。
  • keepAliveTime:最大空闲时间。当核心线程不够而创建了新线程,新线程的最大空闲时间,超过这个时间新线程就会被释放。
  • unit:最大空闲时间单位。
  • workQueue:阻塞队列。用于存放积压的任务。
  • threadFactory:创建新线程的工厂,一般使用默认就可。
  • handler:拒绝策略。

三、线程池工作原理

线程池执行流程

  • 第一步:会判断核心线程数是否已满,如果没有就执行;如果满了就执行第二步。
  • 第二步:判断阻塞队列是否已满。如果没有就加入阻塞队列;如果满了就执行第三步。
  • 第三步:判断最大线程数是否已满。如果没有就创建线程来执行;如果满了就执行拒绝策略。

四、线程池拒绝策略

JDK内置的几种拒绝策略:

  • AbortPolicy(默认):直接抛异常RejectedExecutionException
  • CallerRunsPolicy:将任务交给调用者执行。main线程调用就交给main线程执行。
  • DiscardOldestPolicy:抛弃队列中等待最久的任务。
  • DIscardPolicy:丢弃任务。

AbortPolicy:

    public static class AbortPolicy implements RejectedExecutionHandler {
        /**
         * Creates an {@code AbortPolicy}.
         */
        public AbortPolicy() { }

        /**
         * Always throws RejectedExecutionException.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         * @throws RejectedExecutionException always
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
          // 直接抛出异常
            throw new RejectedExecutionException("Task " + r.toString() +
                                                 " rejected from " +
                                                 e.toString());
        }
    }

CallerRunsPolicy:

    public static class CallerRunsPolicy implements RejectedExecutionHandler {
        /**
         * Creates a {@code CallerRunsPolicy}.
         */
        public CallerRunsPolicy() { }

        /**
         * Executes task r in the caller's thread, unless the executor
         * has been shut down, in which case the task is discarded.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                r.run();
            }
        }
    }

交给调用者执行。

DiscardOldestPolicy:

public static class DiscardOldestPolicy implements RejectedExecutionHandler {
        /**
         * Creates a {@code DiscardOldestPolicy} for the given executor.
         */
        public DiscardOldestPolicy() { }

        /**
         * Obtains and ignores the next task that the executor
         * would otherwise execute, if one is immediately available,
         * and then retries execution of task r, unless the executor
         * is shut down, in which case task r is instead discarded.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                e.getQueue().poll();
                e.execute(r);
            }
        }
    }

将队列头元素抛弃。

DiscardPolicy:

    public static class DiscardPolicy implements RejectedExecutionHandler {
        /**
         * Creates a {@code DiscardPolicy}.
         */
        public DiscardPolicy() { }

        /**
         * Does nothing, which has the effect of discarding task r.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        }
    }

啥也不做,就是抛弃了新的任务。

内置的几种拒绝策略都继承了RejectedExecutionHandler接口,按照这种逻辑,就可以对拒绝策略有自己的扩展。

public class MyRejectedPolicy implements RejectedExecutionHandler {
    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        System.out.println("拒绝执行...");
    }
}

五、生产中的线程池

生产中一般通过ThreadPoolExecutor来创建线程池,所以线程数的设置就相当考究。

根据业务的类型可以分为:

  • CPU密集型
  • IO密集型

当然,跟服务器的硬件配置更是密切相关。

CPU密集型指任务需要大量运算,没有阻塞,CPU一直跑着。CPU密集型一般分配尽可能少的线程数量。

一般公式:CPU核数+1

IO密集型由于不是一直执行任务,应该配置多的线程:比如CPU核数 * 2

但是据小道消息,业内也有使用分配线程数:

CPU核数 / (1-阻塞系数);阻塞系数在0.8~0.9之间。

按照这个公式,一个8核CPU最大可分配的线程数就是:

8 / (1 - 0.9) = 80

个线程数。


六、异步编排

1、创建异步对象
2、计算完成时回调方法

whenComplete可以处理正常和异常的计算结果,exceptionally处理异常情况。
whenComplete和whenCompleteAsync的区别:

  • whenComplete:是执行当前任务的线程继续执行whenComplete任务
  • whenCompleteAsync:把whenCompleteAsync这个任务继续提交给线程池执行

总结:方法以aync结尾的,都会把任务提交给线程池执行,不以async结尾的使用当前线程继续执行。

public static void useSupplyAsyncStartAThreadAndComplete() throws ExecutionException, InterruptedException {
    System.out.println("线程开始...");
    CompletableFuture.supplyAsync(() -> {
        int i = 10 / 0;
        return i;
    }, executor).whenComplete((res, exception) -> {
        System.out.println("执行结果是 -> " + res + "  执行异常是 -> " + exception);
    }).exceptionally((e) -> {
        return 20;  // 这个结果会在线程执行异常时覆盖掉supplyAsync中的返回值
    });
}
3、handle方法

与complete一样,可以处理线程执行结果(包括异常),也有返回值。

public <U> CompletableFuture<U> handle(
    BiFunction<? super T, Throwable, ? extends U> fn) {
    return uniHandleStage(null, fn);
}

public <U> CompletableFuture<U> handleAsync(
    BiFunction<? super T, Throwable, ? extends U> fn) {
    return uniHandleStage(asyncPool, fn);
}

public <U> CompletableFuture<U> handleAsync(
    BiFunction<? super T, Throwable, ? extends U> fn, Executor executor) {
    return uniHandleStage(screenExecutor(executor), fn);
}
public static void useSupplyAsyncStartAThreadAndHandle() throws ExecutionException, InterruptedException {
    System.out.println("线程开始...");
    CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
        int i = 10 / 2;
        return i;
    }, executor).handle((res, e) -> {
        if (res != null) {
            return res;
        }
        if (e != null) {
            System.out.println(e);
            return 11;
        }
        return 0;
    });
    System.out.println("最终结果 -> " + future.get());
}
4、线程串行化方法
// 串行化测试demo
public static void threadSerial(){
    /**
        * 1、thenRun、thenRunAsync 不会接收上一个线程执行结果作为参数、不会有返回
        * 2、.thenAcceptAsync/.thenAccept(res -> {
        *      }): 可以接收上一个线程执行结果作为参数,但不会有返回值
        * 3、thenApply/.thenApplyAsync(res -> {
        *             return 1;
        *         }); : 可以接收上一个线程执行结果作为参数,而且会有返回值
        */
    CompletableFuture.supplyAsync(() -> {
        int i = 10 / 2;
        return i;
    }, executor).thenApplyAsync(res -> {
        return 1;
    });
}
5、两任务组合——都要完成
// 多任务组合测试demo【都完成】
    /**
     * runAfterBoth/runAfterBothAsync: future1和future2执行结束后执行新线程中的,不能接收future2和future1的执行结果作为参数。也不能有返回值
     */
    public static void multiTaskThread_runAfterBoth(){
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            int i = 10 / 2;
            return i;
        }, executor);
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            return "Hello";
        }, executor);

        future1.runAfterBoth(future2, () -> {
            try {
                System.out.println(future1.get());
                System.out.println(future2.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
            System.out.println("world");
        });
    }

    // 多任务组合测试demo【都完成】
    /**
     * thenAcceptBoth/thenAcceptBothAsync: future1和future2执行结束后执行新线程中的,可以接收future2和future1的执行结果作为参数。但不能有返回值
     */
    public static void multiTaskThread_thenAcceptBothAsync(){
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            int i = 10 / 2;
            return i;
        }, executor);
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            return "Hello";
        }, executor);

        future1.thenAcceptBothAsync(future2, (res, res1) -> {
            System.out.println(res + " -> " + res1 + " -> world");
        });
    }

    // 多任务组合测试demo【都完成】
    /**
     * thenCombine/thenCombineAsync: future1和future2执行结束后执行新线程中的,可以接收future2和future1的执行结果作为参数。也可以有返回值
     */
    public static void multiTaskThread_thenCombineAsync() throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            int i = 10 / 2;
            return i;
        }, executor);
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            return "Hello";
        }, executor);

        CompletableFuture<String> result = future1.thenCombineAsync(future2, (res, res1) -> {
            return res + " -> " + res1 + " -> world";
        }, executor);
        System.out.println(result.get());
    }
6、两任务组合——一个完成

    // 多任务组合测试demo【一个完成】
    /**
     * runAfterEitherAsync/runAfterEither:其中组合执行线程中一个线程执行结束就执行后面的线程。不能接收参数,也没有返回值
     */
    public static void multiTaskThread_runAfterEitherAsync(){
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            int i = 10 / 2;
            return i;
        }, executor);
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            return "Hello";
        }, executor);

        future1.runAfterEitherAsync(future2, () -> {
            System.out.println("world");
        });
    }

    // 多任务组合测试demo【一个完成】
    /**
     * acceptEitherAsync/acceptEither:其中组合执行线程中一个线程执行结束就执行后面的线程【这几个线程的返回值类型必须相同】。能接收参数,但是没有返回值
     */
    public static void multiTaskThread_acceptEitherAsync(){
        CompletableFuture<Object> future1 = CompletableFuture.supplyAsync(() -> {
            int i = 10 / 2;
            return i;
        }, executor);
        CompletableFuture<Object> future2 = CompletableFuture.supplyAsync(() -> {
            return "Hello";
        }, executor);

        future1.acceptEitherAsync(future2, (res) -> {
            System.out.println("world");
        });
    }

    // 多任务组合测试demo【一个完成】
    /**
     * applyToEitherAsync/applyToEither: 其中组合执行线程中一个线程执行结束就执行后面的线程【这几个线程的返回值类型必须相同】。能接收参数,也有返回值
     */
    public static void multiTaskThread_applyToEitherAsync(){
        CompletableFuture<Object> future1 = CompletableFuture.supplyAsync(() -> {
            int i = 10 / 2;
            return i;
        }, executor);
        CompletableFuture<Object> future2 = CompletableFuture.supplyAsync(() -> {
            return "Hello";
        }, executor);

        future1.applyToEitherAsync(future2, (res) -> {
            return "world";
        });
    }
7、多任务组合
    // 多任务组合 【等待所有组合的线程执行结束】
    public static void multiTaskThread_allOf() throws ExecutionException, InterruptedException {
        CompletableFuture<Object> future1 = CompletableFuture.supplyAsync(() -> {
            int i = 10 / 2;
            return i;
        }, executor);
        CompletableFuture<Object> future2 = CompletableFuture.supplyAsync(() -> {
            return "Hello";
        }, executor);

        CompletableFuture<Void> future = CompletableFuture.allOf(future1, future2);
        future.get(); // 等待future1和future2执行结束
        /**
         * 注意:CompletableFuture.allOf返回的future.get并不能获取到future1或者 future2的执行结果
         * 要获取future1或者future2的执行结果还是需要调用各自的get方法
         */
        System.out.println(future1.get());
        System.out.println(future2.get());
    }

    // 多任务组合 【等待所有组合的线程中一个执行结束】
    public static void multiTaskThread_anyOf() throws ExecutionException, InterruptedException {
        CompletableFuture<Object> future1 = CompletableFuture.supplyAsync(() -> {
            int i = 10 / 2;
            return i;
        }, executor);
        CompletableFuture<Object> future2 = CompletableFuture.supplyAsync(() -> {
            return "Hello";
        }, executor);

        CompletableFuture<Object> future = CompletableFuture.anyOf(future1, future2);
        future.get(); // 等待future1和future2执行结束
        /**
         * 注意:CompletableFuture.anyOf返回的future.get只能获取成功线程的返回值
         */
        System.out.println(future1.get());
        System.out.println(future2.get());
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值