【从零开始学Java | 第四十三篇】线程池(Thread Pool)

目录

前言

一、什么是线程池?

二、Java中的线程池

1.execute()和submit()的区别

①. execute()

②. submit()

2.自定义线程池

①常见拒绝策略

1. AbortPolicy

2. CallerRunsPolicy

3. DiscardPolicy

4. DiscardOldestPolicy


前言

        在我们之前学习多线程的时候,使用线程往往使用的是new Thread()->{}.start()创建一个线程并启动,这种方法虽然简单,但是在实际场景并不会使用这种方法,因为一旦任务很多,频繁创建和销毁线程,会带来很大的性能损耗,甚至可能把系统拖垮。所以,Java 提供了一个更合理的线程管理方案:线程池(Thread Pool)

一、什么是线程池?

        线程池,顾名思义,就是事先创建好一批线程,统一放到一个池子里进行管理和复用。

        当有任务要执行时,不着急创建一个新的线程,而是首先来到线程池看一下有没有空闲的线程可以复用

        当任务执行完毕后,线程不会销毁而是返回到线程池,供下一次调用。

核心思想:

  • 预先创建一定数量的线程
  • 把待执行的任务放入任务队列
  • 由线程池中的线程不断从队列中取任务执行
  • 线程执行完成后不销毁,继续复用
  • 通过统一策略控制线程数量和任务处理方式

二、Java中的线程池

Executors是一个工具类,用来快速创建线程池。

Executors.newFixedThreadPool(5);        //创建一个有上限的线程池
Executors.newCachedThreadPool();        //创建一个没有上限的线程池

示例:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolDemo {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(3);

        for (int i = 1; i <= 5; i++) {
            int taskId = i;
            executorService.execute(() -> {
                System.out.println("任务 " + taskId + " 由线程 "
                        + Thread.currentThread().getName() + " 执行");
            });
        }

        executorService.shutdown();
    }
}

运行效果:

        线程池中最多有 3 个线程,同时去处理 5 个任务。线程会被复用,而不是每个任务都新建一个线程。

1.execute()和submit()的区别

在线程池中,提交任务常见有两个方法:

  • execute()
  • submit()

①. execute()

executorService.execute(() -> {
System.out.println("执行任务");
});

特点:

  • 只能提交 Runnable
  • 没有返回值
  • 更适合“只关心执行,不关心结果”的任务

②. submit()

Future<Integer> future = executorService.submit(() -> {
return 100;
});

特点:

  • 可以提交 RunnableCallable
  • 有返回值
  • 返回 Future 对象,可以获取执行结果

2.自定义线程池

线程池常用的构造方法如下:

public ThreadPoolExecutor(
        int corePoolSize,
        int maximumPoolSize,
        long keepAliveTime,
        TimeUnit unit,
        BlockingQueue<Runnable> workQueue,
        ThreadFactory threadFactory,
        RejectedExecutionHandler handler
)

corePoolSize(核心线程数):线程池中长期保留的线程数量。当任务到来时,线程池会优先创建线程,直到线程数达到 corePoolSize

maximumPoolSize(最大线程数):线程池允许创建的最大线程数量。如果核心线程都在忙,并且队列也已经满了,线程池就会创建非核心线程,直到总数达到maximumPoolSize。

keepAliveTime(非核心线程空闲存活时间):当线程池中的线程数大于核心线程数时,多出来的那些非核心线程,如果空闲时间超过 keepAliveTime,就会被回收。

unit(时间单位):keepAliveTime 的时间单位。

workQueue(任务队列):当核心线程都在工作时,新来的任务会被放到任务队列中等待执行。

threadFactory(线程工厂):用于创建线程。

handler(拒绝策略):当线程池无法继续接收新任务时,会执行拒绝策略。

①常见拒绝策略

1. AbortPolicy

默认策略。

直接抛出异常:

RejectedExecutionException

适合对任务丢失非常敏感的场景。

2. CallerRunsPolicy

由提交任务的线程自己执行该任务。

这会让提交任务的线程“背压”,减缓任务提交速度。

3. DiscardPolicy

直接丢弃任务,不抛异常。

适合允许部分任务丢失的场景,但风险较大。

4. DiscardOldestPolicy

丢弃队列中最早的任务,然后尝试提交当前任务。

适合对“最新任务更重要”的场景。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值