线程池基本原理

        线程池(Thread Pool)是一种管理和复用线程的机制,它在多线程编程中被广泛使用,主要目的是提高线程的利用率和性能,减少线程创建和销毁的开销。线程池通过预先创建一定数量的线程,并维护一个任务队列,有效地处理多个任务。

一、原理及工作流程 

    1、线程池初始化: 

  • 在创建线程池时,会指定池中的初始线程数量、最大线程数量、空闲线程的存活时间等参数。
  • 线程池通常由一个线程池管理器(ThreadPoolExecutor 或 Executors 工厂类)负责创建和管理。

    2、任务提交

  • 当有任务需要执行时,可以将任务提交给线程池。
  • 任务可以是实现了 Runnable 接口或 Callable 接口的对象。

    3、任务队列

  • 线程池维护一个任务队列(通常是一个阻塞队列),用于存储提交但尚未执行的任务。
  • 如果当前线程数未达到上限,并且有空闲线程,则任务会被分配给空闲线程执行;否则,任务会被放入任务队列等待执行

    4、线程执行任务

  • 当有空闲线程可用时,线程池将任务从队列中取出,分配给空闲线程执行。
  • 如果所有线程都在执行任务且任务队列已满(通常由队列类型决定是否会阻塞或抛出异常),线程池根据配置的策略(如丢弃、阻塞、调用者运行等)处理新任务的提交。

    5、线程回收

  • 如果一个线程在一定时间内未被使用(空闲时间超过设定的存活时间),线程池可能会关闭并移除这个线程,以节省资源。
  • 但如果线程池中的线程数低于初始数目,有些线程池实现会保持一定数量的核心线程,以避免频繁地创建和销毁线程。

二、ThreadPoolExecutor 参数说明 

    ThreadPoolExecutor 是一个强大的线程池实现类,它提供了多个参数来配置线程池的行为,这些参数可以根据实际需求进行调整,以优化线程的使用和任务的执行。以下是 ThreadPoolExecutor 的主要参数及其说明: 

    1、corePoolSize: 

    核心线程数。线程池中始终存活的线程数量,即使它们处于空闲状态也不会被销毁,除非设置了 allowCoreThreadTimeOut(true)。这个值通常设置为能够快速处理任务的数量,即使线程空闲也能保持响应能力。

    2、maximumPoolSize

    最大线程数。线程池中允许存在的最大线程数量。当工作队列已满且线程数小于最大线程数时,线程池会创建新的线程来处理任务,直到达到最大线程数为止。

    3、 keepAliveTime

    线程空闲时间。当线程数大于核心线程数时,多余的空闲线程在终止之前等待新任务的最长时间。超过这个时间,多余的线程将被销毁,直到线程数量等于核心线程数为止。

    4、unit

    线程空闲时间的单位。通常使用 TimeUnit 中的枚举值,例如 TimeUnit.MILLISECONDS 表示毫秒。

    5、workQueue

  工作队列。用于保存等待执行的任务的阻塞队列。可以选择不同的队列实现,如 ArrayBlockingQueueLinkedBlockingQueueSynchronousQueue 等,每种队列实现都有其特点和适用场景 。

    6、threadFactory

    线程工厂。用于创建新线程,默认情况下使用 Executors.defaultThreadFactory() 创建线程。通过自定义线程工厂,可以为线程池中的线程设置特定的名称、优先级等属性。

    7、handler

    拒绝策略。当任务添加到线程池中被拒绝时的处理策略。常见的策略包括 AbortPolicy(默认,抛出异常)、CallerRunsPolicy(调用者执行任务)、DiscardPolicy(默默丢弃任务)、DiscardOldestPolicy(丢弃队列中最老的任务)。

三、ThreadPoolExecutor 拒绝策略 

   ThreadPoolExecutor 在任务提交到线程池时可能会遇到无法处理的情况,这时就会触发拒绝策略。拒绝策略定义了线程池无法继续接受新任务时的处理方式。Java 提供了四种预定义的拒绝策略,同时也支持自定义拒绝策略。 

    1、AbortPolicy(默认策略):

    当任务添加到线程池被拒绝时,会抛出 RejectedExecutionException 异常。这是默认的拒绝策略,会立即抛出异常,防止任务堆积导致系统不可控。

ThreadPoolExecutor executor = new ThreadPoolExecutor(
    corePoolSize, maxPoolSize, keepAliveTime, unit,
    workQueue, Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());

    2、CallerRunsPolicy

    当任务添加到线程池被拒绝时,会由添加任务的线程执行被拒绝的任务。这种策略不会丢弃任务,而是由调用者自己来执行该任务,从而降低新任务的提交速度。

ThreadPoolExecutor executor = new ThreadPoolExecutor(
    corePoolSize, maxPoolSize, keepAliveTime, unit,
    workQueue, Executors.defaultThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy());

    3、DiscardPolicy

    当任务添加到线程池被拒绝时,会默默地丢弃被拒绝的任务。这种策略会造成任务的丢失,不建议在需要高可靠性的系统中使用。

ThreadPoolExecutor executor = new ThreadPoolExecutor(
    corePoolSize, maxPoolSize, keepAliveTime, unit,
    workQueue, Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardPolicy());

    4、DiscardOldestPolicy

    当任务添加到线程池被拒绝时,会丢弃队列中最老的一个任务,然后尝试重新提交被拒绝的任务。

ThreadPoolExecutor executor = new ThreadPoolExecutor(
    corePoolSize, maxPoolSize, keepAliveTime, unit,
    workQueue, Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardOldestPolicy());

四、代码示例 

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class CustomThreadPoolExample {
    public static void main(String[] args) {
        // 定义线程池参数
        int corePoolSize = 5; // 核心线程数
        int maxPoolSize = 10; // 最大线程数
        long keepAliveTime = 5000; // 线程空闲时间
        ArrayBlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(10); // 工作队列

        // 创建 ThreadPoolExecutor
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                corePoolSize,
                maxPoolSize,
                keepAliveTime,
                TimeUnit.MILLISECONDS,
                workQueue,
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.DiscardOldestPolicy());//DiscardOldestPolicy策略

        // 提交任务给线程池执行
        for (int i = 0; i < 15; i++) {
            Runnable task = new Task(i);
            executor.execute(task);
        }

        // 关闭线程池
        executor.shutdown();
    }

    // 任务类
    static class Task implements Runnable {
        private int taskId;

        public Task(int id) {
            this.taskId = id;
        }

        @Override
        public void run() {
            System.out.println("任务ID : " + taskId + "被" + Thread.currentThread().getName() + "执行");
            try {
                Thread.sleep(1000); // 模拟任务执行时间
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
  • 11
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

真真假假々

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值