JAVA 线程池

1 线程池的优势

在多线程编程时,创建线程是十分消耗资源的,当线程创建过多时,便会引发内存溢出,因此引入了线程池技术。其实就是⼀个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源。总体来说,线程池有如下的优势:

  1. 降低资源消耗: 通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
  2. 提高响应速度: 当任务到达时,任务可以不需要等到线程创建就能立即执行。
  3. 提高线程的可管理性: 线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

在这里插入图片描述

2 线程池的创建

线程池的创建有两种方式

2.1 使用ThreadPoolExecutor自定义创建线程池

部分源码:

public ThreadPoolExecutor(int corePoolSize,//核心线程数量
                              int maximumPoolSize,//     最大线程数
                              long keepAliveTime, //       最大空闲时间
                              TimeUnit unit,         //        时间单位
                              BlockingQueue<Runnable> workQueue,   //   任务队列
                              ThreadFactory threadFactory,    // 线程工厂
                              RejectedExecutionHandler handler  //  饱和处理机制
}

参数说明

  • corePoolSize(必需):核心线程数。默认情况下,核心线程会一直存活,但是当将 allowCoreThreadTimeout 设置为 true 时,核心线程也会超时回收。
  • maximumPoolSize(必需):线程池所能容纳的最大线程数。当活跃线程数达到该数值后,后续的新任务将会阻塞。
  • keepAliveTime(必需):线程闲置超时时长。如果超过该时长,非核心线程就会被回收。如果将 allowCoreThreadTimeout 设置为 true 时,核心线程也会超时回收。
  • unit(必需):指定 keepAliveTime 参数的时间单位。常用的有:TimeUnit.MILLISECONDS(毫秒)、TimeUnit.SECONDS(秒)、TimeUnit.MINUTES(分)。
  • workQueue(必需):任务队列。通过线程池的 execute() 方法提交的 Runnable 对象将存储在该参数中。其采用阻塞队列实现。
  • threadFactory(可选):线程工厂。用于指定为线程池创建新线程的方式。
  • handler(可选):拒绝策略。当达到最大线程数时需要执行的饱和策略。

2.2 使用Executors工厂来创建

常用线程池

方法说明
newFixedThreadPool创建一个可重复固定的线程数的线程池
newCachedThreadPool创建一个可缓存的线程池,调用execute将重复用以前构造的线程(如果当前线程可用)。如果没有可用线程则创建新的线程并加入到池中。终止并从缓存中移除那些已有60s未被使用的线程。
newSingleThreadExecutor创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行
newScheduledThreadPool创建一个支持定时及周期性的任务执行的线程池,多数情况下可用来替代Timer类。

2.3 线程池的使用

// 创建线程池
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(CORE_POOL_SIZE,
                   MAXIMUM_POOL_SIZE,
                   KEEP_ALIVE,
                   TimeUnit.SECONDS,
                   sPoolWorkQueue,
                  sThreadFactory);
// 向线程池提交任务
threadPool.execute(new Runnable() {
    @Override
    public void run() {
        ... // 线程执行的任务
    }
});
// 关闭线程池
threadPool.shutdown(); // 设置线程池的状态为SHUTDOWN,然后中断所有没有正在执行任务的线程
threadPool.shutdownNow(); // 设置线程池的状态为 STOP,然后尝试停止所有的正在执行或暂停任务的线程,并返回等待执行任务的列表

3 功能线程池

3.1 定长线程池(FixedThreadPool)

特点: 只有核心线程,线程数量固定,执行完立即回收,任务队列为链表结构的有界队列。
应用场景: 控制线程最大并发数。
示例代码

public class Demo {
    public static void main(String[] args) throws InterruptedException {

        ExecutorService pool = Executors.newFixedThreadPool(2);
        Runnable task = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println(Thread.currentThread().getName() + ": " + i);
                }
            }
        };
        // 线程池可以用来执行任务(Runnable/Callable)  submit(Runnable/Callable)/execute(Runnable)
        pool.submit(task);
        pool.submit(task);

        pool.submit(task);

        // 释放资源
        pool.shutdown();
        // 线程池关闭后, 不能再执行新的任务
        pool.submit(task);
    }
}

3.2 定时线程池(ScheduledThreadPool )

特点: 核心线程数量固定,非核心线程数量无限,执行完闲置 10ms 后回收,任务队列为延时阻塞队列。
应用场景: 执行定时或周期性的任务。
示例代码

public class Demo {
    public static void main(String[] args) throws InterruptedException {

        ScheduledExecutorService pool = Executors.newScheduledThreadPool(2);
        Runnable task = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println(Thread.currentThread().getName() + ": " + i);
                }
            }
        };
        Object obj = new Object();
        // 线程池可以用来执行任务(Runnable/Callable)  submit(Runnable/Callable)/execute(Runnable)
        pool.schedule(task, 5000, TimeUnit.MILLISECONDS);
//        pool.submit(task);
//
//        pool.submit(task);
        // 释放资源
        pool.shutdown();

    }
}

3.3 可缓存线程池(CachedThreadPool)

特点: 无核心线程,非核心线程数量无限,执行完闲置 60s 后回收,任务队列为不存储元素的阻塞队列。
应用场景: 执行大量、耗时少的任务。

示例代码

public class Demo {
    public static void main(String[] args) throws InterruptedException {

        ExecutorService pool = Executors.newCachedThreadPool();
        Runnable task = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println(Thread.currentThread().getName() + ": " + i);
                }
            }
        };
        // 线程池可以用来执行任务(Runnable/Callable)  submit(Runnable/Callable)/execute(Runnable)
        pool.submit(task);
        pool.submit(task);
        pool.submit(task);

        Thread.sleep(3000);
        // 线程池中的线程可以重复使用
        pool.submit(task);
        pool.submit(task);
        pool.submit(task);
        // 如果超出了线程池中的线程数, 根据需求会创建新的线程对象
        pool.submit(task);

        System.out.println("主方法结束");
        // 释放资源
        pool.shutdown();
    }
}

3.4 单线程化线程池(SingleThreadExecutor)

特点: 只有 1 个核心线程,无非核心线程,执行完立即回收,任务队列为链表结构的有界队列。
应用场景: 不适合并发但可能引起 IO 阻塞性及影响 UI 线程响应的操作,如数据库操作、文件操作等。

示例代码

public class Demo {
    public static void main(String[] args) throws InterruptedException {

        ExecutorService pool = Executors.newSingleThreadExecutor();
        Runnable task = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println(Thread.currentThread().getName() + ": " + i);
                }
            }
        };
        // 线程池可以用来执行任务(Runnable/Callable)  submit(Runnable/Callable)/execute(Runnable)
        pool.submit(task);
        pool.submit(task);

        pool.submit(task);

        // 释放资源
        pool.shutdown();

    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值