线程池 核心原理

线程池核心原理

线程池的核心原理是基于“池化”(Pooling)思想,这种思想在计算机科学中广泛应用,例如数据库连接池、对象池等。线程池的主要目的是为了减少线程创建和销毁的开销,提高线程的复用性,从而提高程序的性能和响应速度。以下是线程池的核心原理:

  • 线程复用:线程池中维护了一组工作线程(Worker Threads),这些线程被创建后不会立即销毁,而是用于执行多个任务。当任务到达时,线程池会从池中选出一个空闲的线程来执行任务,而不是每次都创建新线程。
  • 任务队列:线程池通常配备了一个任务队列(Work Queue),用于存储待执行的任务。当所有工作线程都处于忙碌状态时,新提交的任务会被放入队列中等待空闲线程。
  • 线程管理:线程池内部会管理线程的生命周期,包括线程的创建、销毁、工作线程的数量等。线程池会根据配置的核心线程数(Core Pool Size)和最大线程数(Maximum Pool Size)来控制线程的数量。
  • 任务分配:线程池中的任务分配器(Task Scheduler)负责从任务队列中取出任务,并将任务分配给空闲的工作线程。
  • 动态线程管理:线程池可以根据当前负载动态地调整线程数量。例如,当任务队列满了,并且所有核心线程都处于忙碌状态时,线程池可能会创建新的线程,直到达到最大线程数。
  • 拒绝策略:当线程池达到最大线程数,并且任务队列已满时,线程池会根据预定义的拒绝策略来处理新提交的任务。常见的拒绝策略包括抛出异常、直接丢弃任务、丢弃队列中最老的任务等。

ThreadPoolExecutor

ThreadPoolExecutor 是 Java 中线程池的核心实现,位于 java.util.concurrent 包下。它提供了线程池的基本功能,包括线程的创建、任务的执行、线程的回收等,并允许开发者自定义线程池的行为。

主要构造函数:

ThreadPoolExecutor(int corePoolSize,
                   int maximumPoolSize,
                   long keepAliveTime,
                   TimeUnit unit,
                   BlockingQueue<Runnable> workQueue,
                   ThreadFactory threadFactory,
                   RejectedExecutionHandler handler)
  • corePoolSize:核心线程数,即始终存在的线程数量。
  • maximumPoolSize:最大线程数,即线程池中允许的最大线程数量。
  • keepAliveTime:非核心线程的空闲存活时间。
  • unit:keepAliveTime 的时间单位。
  • workQueue:用于存放任务的阻塞队列。
  • threadFactory:线程工厂,用于创建新线程。
  • handler:拒绝策略,用于处理当线程池和队列都满时新提交的任务。

执行任务:

ThreadPoolExecutor 提供了多个方法来执行任务:

  • execute(Runnable command):执行一个 Runnable 任务。
  • submit(Runnable task):提交一个 Runnable 任务,并返回一个 Future 对象,可以通过这个对象获取任务执行的结果(如果有)。
  • submit(Callable task):提交一个 Callable 任务,并返回一个 Future 对象,可以通过这个对象获取任务执行的结果。

关闭线程池:

ThreadPoolExecutor 可以通过以下方法来关闭:

  • shutdown():启动线程池的关闭序列,不再接受新任务,但会继续执行所有已经提交的任务。
  • shutdownNow():尝试立即停止所有正在执行的任务,并返回尚未开始执行的任务列表。

线程池生命周期:

ThreadPoolExecutor 定义了线程池的生命周期状态,包括:

  • RUNNING:接受新任务并处理队列中的任务。
  • SHUTDOWN:不接受新任务,但处理队列中的任务。
  • STOP:不接受新任务,不处理队列中的任务,并尝试中断正在执行的任务。
  • TIDYING:所有任务都已终止,线程池正在转换为 TERMINATED 状态。
  • TERMINATED:线程池已终止。

Executor框架

Executor框架是Java 5引入的一个用于并发编程的框架,它提供了任务执行和异步任务管理的工具。这个框架的主要目的是简化线程的使用和管理,使得开发者可以更加专注于任务的逻辑,而不是线程的创建和管理。Executor框架的主要组件包括:

Executor接口:

  • 这是框架的基础,一个简单的接口,定义了执行任务的方法 execute(Runnable command)。

ExecutorService接口:

  • 继承自Executor接口,提供了更多管理任务执行的方法,如 submit()、shutdown()、shutdownNow() 等。
  • 它还提供了用于批量执行任务的方法,如 invokeAll() 和 invokeAny()。

ThreadPoolExecutor类:

  • ExecutorService接口的一个实现,是一个灵活的线程池实现,允许开发者自定义线程池的参数和行为。

ScheduledExecutorService接口:

  • 继承自ExecutorService,提供了定时任务执行的方法,如 schedule()、scheduleAtFixedRate()、scheduleWithFixedDelay()。

ScheduledThreadPoolExecutor类:

  • ScheduledExecutorService接口的一个实现,用于执行定时任务和周期性任务。

Future接口:

  • 表示异步计算的结果,提供了检查计算是否完成、等待计算完成、获取计算结果、取消计算等方法。

Callable接口:

  • 与Runnable类似,但它允许任务返回一个结果或抛出一个异常。

Executor框架的使用通常涉及以下步骤:

  • 创建ExecutorService实例,例如通过ThreadPoolExecutor或Executors工厂类。
  • 提交Runnable或Callable任务到ExecutorService。
  • 使用Future来获取任务的结果(如果任务提交时使用了submit()方法)。
  • 关闭ExecutorService,防止新任务的提交,并等待所有任务执行完成。

线程池实战

使用线程池的实战通常涉及到java.util.concurrent包中的ExecutorService和ThreadPoolExecutor类。以下是一个简单的示例,展示了如何使用线程池来执行多个任务。

步骤1:创建线程池

首先,我们需要创建一个线程池。我们可以使用Executors工厂类来创建一个固定大小的线程池,也可以直接使用ThreadPoolExecutor构造函数来定制线程池。

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

// 创建一个固定大小的线程池,包含5个线程
ExecutorService executorService = Executors.newFixedThreadPool(5);

步骤2:创建任务

接下来,我们创建一个实现Runnable接口的任务类。

import java.util.concurrent.TimeUnit;

public class MyTask implements Runnable {
    private final int taskId;

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

    @Override
    public void run() {
        System.out.println("开始执行任务:" + taskId);
        try {
            // 模拟任务执行需要一段时间
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("任务:" + taskId + " 执行完成");
    }
}

步骤3:提交任务到线程池

现在我们可以将任务提交到线程池中执行。

for (int i = 0; i < 10; i++) {
    executorService.submit(new MyTask(i));
}

步骤4:关闭线程池

最后,当我们不再需要线程池时,应该关闭它以释放资源。

executorService.shutdown();

完整示例

将上述步骤组合在一起,我们得到一个完整的线程池使用示例。

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

public class ThreadPoolExample {
    public static void main(String[] args) {
        // 创建一个固定大小的线程池,包含5个线程
        ExecutorService executorService = Executors.newFixedThreadPool(5);

        // 提交任务到线程池
        for (int i = 0; i < 10; i++) {
            executorService.submit(new MyTask(i));
        }

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

class MyTask implements Runnable {
    private final int taskId;

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

    @Override
    public void run() {
        System.out.println("开始执行任务:" + taskId);
        try {
            // 模拟任务执行需要一段时间
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("任务:" + taskId + " 执行完成");
    }
}

我们创建了一个包含5个线程的线程池,并提交了10个任务。由于线程池的大小限制,一次只能执行5个任务,其他任务会在队列中等待。每个任务模拟执行2秒,然后输出完成信息。
在实际应用中,线程池的使用会更加复杂,可能需要根据应用程序的特定需求来调整线程池的大小和配置,以及处理任务执行中的异常和结果。

相关推荐

  1. 线 核心原理

    2024-04-01 13:54:02       41 阅读
  2. Tomcat线原理(下篇:工作原理)

    2024-04-01 13:54:02       59 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-01 13:54:02       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-01 13:54:02       106 阅读
  3. 在Django里面运行非项目文件

    2024-04-01 13:54:02       87 阅读
  4. Python语言-面向对象

    2024-04-01 13:54:02       96 阅读

热门阅读

  1. c++ 设计模式 桥模式

    2024-04-01 13:54:02       38 阅读
  2. pytorch中nn.GroupNorm()作用及参数说明

    2024-04-01 13:54:02       48 阅读
  3. Let`s move - sui move开发实战-dao(5)反馈

    2024-04-01 13:54:02       44 阅读
  4. el-dialog宽度自适应

    2024-04-01 13:54:02       44 阅读
  5. 04_Linux磁盘和文件系统

    2024-04-01 13:54:02       40 阅读
  6. 使用Jackson进行序列化和反序列化

    2024-04-01 13:54:02       37 阅读
  7. Android笔记--MediaCodec(一)

    2024-04-01 13:54:02       36 阅读
  8. 英国生物数据库的申请流程

    2024-04-01 13:54:02       40 阅读
  9. flask+uwsgi+云服务器 部署服务端

    2024-04-01 13:54:02       41 阅读