线程池相关知识点

一、线程池的概念及重要性

1.1 什么是线程池?

线程池(Thread Pool)是一种基于池化技术的线程使用模式,它允许多个线程复用,可以有效地管理线程资源,避免频繁地创建和销毁线程带来的高开销。

1.2 为什么要使用线程池?

如果每次需要执行并行任务时都创建新线程,系统将花费大量时间和资源在线程的创建和销毁上。这就像是每次需要一辆车时就购买一辆新车,使用后立即报废。线程池的出现,就是为了解决这一问题,提高资源利用率,降低开销。

二、Java中线程池的核心组件

2.1 ThreadPoolExecutor

ThreadPoolExecutor 是Java中最基本的线程池实现,它提供了丰富的构造器,允许开发者灵活配置线程池的各种参数。

2.2 Executors类

Java还提供了一个工具类 Executors,它封装了一些常用的线程池配置,比如单线程池、固定大小线程池等,让开发者可以更加便捷地创建线程池。

三、Java线程池的工作原理

3.1 线程池的状态

线程池在Java中的实现涉及到几种状态,例如RUNNING、SHUTDOWN等,这些状态定义了线程池在不同情况下的行为。

3.2 任务的执行流程

当一个任务被提交到线程池时,线程池会首先尝试使用空闲的线程来执行任务。如果没有空闲线程,且当前线程数未达到核心线程数,则创建新的线程。如果达到了,则加入队列等待执行。如果队列也满了,则尝试创建新的线程直到达到最大线程数,超过这个数则执行拒绝策略。

四、线程池中的关键参数

4.1 核心线程数(corePoolSize)

这是线程池中始终存活的线程数量,即使它们处于闲置状态。

4.2 最大线程数(maximumPoolSize)

线程池允许创建的最大线程数。

4.3 存活时间(keepAliveTime)

当线程池中的线程数量超过核心线程数时,这些多余的线程在空闲时间超过keepAliveTime值时将会被终止。

4.4 工作队列(workQueue)

存储那些已经提交但还未被执行的任务。

4.5 线程工厂(threadFactory)

用于创建新线程的工厂。

4.6 拒绝策略(handler)

当任务太多,无法被及时处理时,如何拒绝新任务。

五、Java线程池的使用示例

在Java中创建和使用线程池:

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

public class ThreadPoolDemo {
    public static void main(String[] args) {
        // 创建固定大小的线程池
        ExecutorService executor = Executors.newFixedThreadPool(5);

        for (int i = 0; i < 10; i++) {
            Runnable worker = new WorkerThread("" + i);
            executor.execute(worker);
        }

        executor.shutdown();
        while (!executor.isTerminated()) {
        }

        System.out.println("Finished all threads");
    }
}

class WorkerThread implements Runnable {
    private String command;

    public WorkerThread(String s) {
        this.command = s;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " Start. Command = " + command);
        processCommand();
        System.out.println(Thread.currentThread().getName() + " End.");
    }

    private void processCommand() {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

这段Java代码展示了如何使用 ExecutorService 来管理一个固定大小的线程池,并执行多个任务。

类和方法解释

  1. ThreadPoolDemo 类:

    • 这是一个包含 main 方法的类,它是整个程序的入口。
    • main 方法中,首先通过 Executors.newFixedThreadPool(5) 创建一个包含5个线程的固定大小的线程池。这意味着线程池会一直维持5个线程,即使有的线程暂时没任务执行。
  2. WorkerThread 类:

    • 这是实现了 Runnable 接口的类,用于定义线程任务的具体行为。
    • 构造函数接受一个字符串参数 s,此参数用于标识或命名具体的工作线程。
    • run 方法是 Runnable 接口的一部分,它定义了线程的执行逻辑。
      • 输出开始执行的消息。
      • 调用 processCommand 方法模拟任务执行,这里通过 Thread.sleep(5000) 模拟了一个耗时5秒的任务。
      • 输出完成执行的消息。

程序执行流程

  1. 创建线程池:

    • 程序通过 Executors.newFixedThreadPool(5) 创建一个固定大小为5的线程池。
  2. 提交任务:

    • 使用一个 for 循环,创建并提交10个 WorkerThread 任务到线程池。每个任务被标记一个从0到9的数字。
    • 由于线程池的大小是5,因此在任何时间点,最多只有5个线程会同时执行。其余的任务会在线程池中等待,直到有线程变为可用。
  3. 关闭线程池:

    • executor.shutdown() 调用开始线程池的关闭过程。这不会立即关闭线程池,而是等待所有已提交的任务执行完毕。
    • while (!executor.isTerminated()) {} 是一个等待循环,它会一直循环,直到线程池完全终止,即所有任务都执行完毕。
  4. 输出完成消息:

    • 当所有任务都执行完成后,输出 “Finished all threads”,表示程序执行。

注意点

  • 使用线程池可以有效管理和复用程,避免了频繁创建和销毁线程的开销,提高了资源的利用率和程序的性能。
  • 需要,shutdown() 方法并不会立即停止线程池,而是不再接受新的任务,等待所有已提交的任务完成。如果需要立即停止,可以使用 shutdownNow() 方法,但这可能会导致正在执行的任务突然中断。
  • 此代码在等待线程池关闭时使用了一个空的 while 循环,这在实际应用中可能不是最佳做法,因为它会导致CPU资源的浪费。更好的方法是使用 awaitTermination 方法配合适当的超时设置。

六、线程池的优化及注意事项

6.1 选择合适的队列类型

根据任务的性质选择合适的队列类型,如无界队列、有界队列等,对于不同的应用场景,选择不同的队列类型可以显著影响程序的性能。

6.2 监控线程池状态

实时监控线程池的状态,如线程数量、活跃程度及队列大小等,对于及时调整线程池策略至关重要。

6.3 避免资源竞争

确保线程池中的线程不会因为竞争同一资源而导致效率低下。

  • 14
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

懒人w

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

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

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

打赏作者

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

抵扣说明:

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

余额充值