快速了解线程池

一. 线程池初了解

1. 什么是线程池

线程池是一种采用池化思想(同理还有常量池,内存池等)来管理和复用线程的技术。线程池中有若干已经创建的线程和一个存放执行任务的阻塞队列,当队列中有待执行的任务时线程可以直接取出并执行,对于已经执行完任务的线程并不会直接销毁,而是进行适当地复用以处理更多的多线程任务,从而达到提高程序性能 和 降低系统开销的目的。

2. 使用线程池的好处

  1. 提高程序的响应速度:线程池中管理了若干已经创建的线程,当新任务到来时无需进行线程的创建就可对任务进行处理。
  2. 降低系统的开销:线程池可以对已经创建的线程进行复用,避免了频繁创建和销毁线程带来的系统开销。
  3. 提高线程的可管理性:线程池可以对线程进行统一的分配、调优和监控。

二. 线程池再了解

在Java中,ExecutorService 是管理线程池和所提交的任务的重要接口,它表示一个线程池示例,通过该接口的方法我们可以了解线程池基本方法的使用(如下表)。
其中 ThreadPoolExecutor类 是 ExecutorService接口的一个主要实现类,获得线程池主要有两种方法:(1)直接实例化ThreadPoolExecutor类,并手动对ThreadPoolExecutor类进行参数配置(2)通过Executors这个工厂类的工厂方法获取ThreadPoolExecutor类。

ExecutorService的主要方法:
在这里插入图片描述

1. ThreadPoolExecutor类的重要配置

若通过直接实例化的方式获取 ThreadPoolExecutor类,可通过以下参数对线程池进行相关的配置。

  1. corePoolSize(核心线程数):当线程池空闲时,即线程池中队列没有待执行任务时仍然保留的线程数量。
  2. maximumPoolSize(最大线程数):线程池允许存在的最大线程数,当待处理任务减少时,部分线程可能会被销毁,即 corePoolSize <= 线程数量 <= maximumPoolSize。
  3. keepAliveTime(最长空闲存活时间):当线程数量大于核心线程数时,多余线程被允许存活的最长时间,超过该时间未执行新任务的多余线程将被销毁。
  4. unit(时间单位):keepAliveTime参数的时间单位。
  5. workQueue(工作队列):传递任务的阻塞队列,可根据不同需求指定不同的队列类型;若对任务的优先级有要求,可选择PriorityBlockingQueue,若任务数量变动较大,可选择LinkedBlockingQueue等。
  6. threadFactory(创建线程的工厂):使用 ThreadFactory工厂类来创建线程,可以自动对线程相关属性进行设置。
  7. handle(拒绝策略):当阻塞队列中待处理的任务数量达到队列的最大容量时,对继续添加的任务采取适当的拒绝策略(4种)。

在这里插入图片描述

2. 线程池的工作流程

在这里插入图片描述

3. 使用Java标准库创建线程

在Java标准库中,主要通过 Executors这个工厂类的4个主要方法来获取线程池 ThreadPoolExecutor类 的实例,但方法的返回值为 ThreadPoolExecutor类 的实现接口 ExecutorService。(方法简介如下)
在这里插入图片描述

使用示例如下:
Executors.newCachedThreadPool()

public static void main(String[] args) throws InterruptedException {
    // 创建一个 线程数目动态变化的 线程池
    // 当线程池中的任务数 较少时,会适当的销毁线程;当待执行的任务数较多时, 会适当地创建更多 新的线程以执行任务
    ExecutorService service = Executors.newCachedThreadPool();
    for (int i = 0; i < 20; i++) {
        int id = i;
        service.submit(() -> {
            System.out.println("i = " + id);
        });
    }
}    

部分执行结果如下:
在这里插入图片描述

==========分割线
Executors.newSingleThreadPool():队列任务为顺序执行

public static void main(String[] args) throws InterruptedException {
    // 创建一个 只有一个线程 执行线程任务的线程池
    // 线程池每次只能执行 一个线程任务, 多余的任务会在任务队列中等待执行
    ExecutorService service = Executors.newSingleThreadExecutor();
    for (int i = 0; i < 20; i++) {
        int id = i;
        service.submit(() -> {
            System.out.println("i = " + id);
        });
    }
}    

在这里插入图片描述

三. 模拟实现简易线程池

实现线程池,需要有一个阻塞队列来存放执行任务和若干线程执行任务,并在队满时继续提交任务执行一定的拒绝策略(这里采用阻塞等待的方式)。

具体的步骤如下:

  1. 在线程池实例化时创建一定数量的线程,每个线程的工作内容是利用循环的方式扫描是否有待执行任务,若有则取出队列任务并执行。
  2. 创建固定容量的阻塞队列(ArrayBlockingQueue)用于接收添加任务。
  3. 为线程池提供提交任务的方法。

具体代码如下:

class MyThreadPool {
    // 用来存放线程池中 要执行的任务
     BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(50);

     public MyThreadPool(int n) {
         for (int i = 0; i < n; i++) {
             Thread t = new Thread(() -> {
                // 每个线程采用死循环的方式扫描是否有待执行的任务
                while (true) {
                    try {
                        Runnable task = queue.take();
                        task.run();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }

                }
             });
             t.start();
         }
     }

     // 向线程池中添加任务
     public void submit(Runnable runnable) throws InterruptedException {
         queue.put(runnable);
     }

}

以上就是本篇文章的全部内容了,如果这篇文章对你有些许帮助,你的点赞、收藏和评论就是对我最大的支持。
另外,文章的不足之处,也希望你可以给我一点小小的建议,我会努力检查并改进。

  • 24
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值