博客
关于我
并发--线程池--Executors
阅读量:505 次
发布时间:2019-03-07

本文共 6015 字,大约阅读时间需要 20 分钟。

Java 线程池常见种类与使用方法

随着现代应用程序对并发处理要求的不断提高,Java 的线程池机制成为开发者的利手工具。本文将介绍 Java 线程池的几种常见种类及其使用方法,帮助开发者更好地理解线程池的特性和适用场景。

一、线程池的简介

线程池是一种资源管理的机制,它允许程序高效地配置和使用多个线程来执行任务。通过线程池,开发者无需手动管理线程的生命周期,而是通过任务提交的方式,线程池会根据需求自动创建、管理和终止线程。常见的线程池种类包括 固定大小单个定时缓存

二、线程池的创建方法

1. 固定大小线程池

使用 Executors.newFixedThreadPool(int nThreads) 创建固定大小的线程池。

ExecutorService executor = Executors.newFixedThreadPool(3);
  • 特点:线程池中始终保持指定数量的核心线程(corePoolSize)。当线程数量达到最大值后,新任务会被 enqueue至队列中,直到核心线程空闲。
// 创建固定大小线程池ExecutorService executor = Executors.newFixedThreadPool(3);// 提交任务for (int i = 0; i < 6; i++) {    executor.execute(new MyTask(i));}executor.shutdown();

2. 单个线程池

使用 Executors.newSingleThreadExecutor() 创建单线程池。

ExecutorService executor = Executors.newSingleThreadExecutor();
  • 特点:只创建一个核心线程处理所有任务,任务按提交顺序串行执行。
  • 优点:任务执行顺序明确,不会出现任务乱序。
  • 缺点:如果线程被异常终止,会重新创建线程继续任务执行。
// 创建单线程定时池ExecutorService executor = Executors.newSingleThreadScheduledExecutor();// 定期执行任务executor.scheduleAtFixedDelay(new Runnable(), 0, 5, TimeUnit.SECONDS);

3. 定时线程池

  • 如果需要周期性执行任务,可以使用 ScheduledThreadPoolExecutor
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(3);
  • 适用于任务需要在特定时间间隔后执行的情况。

4. 缓存线程池

使用 ThreadPoolExecutor 的构造方法直接指定 corePoolSizemaxPoolSize

new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS, new SynchronousQueue<>());
  • 特点:支持动态创建和回收线程,适用于任务负载波动较大的场景。
// 创建缓存线程池ExecutorService executor = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS, new SynchronousQueue<>());

三、固定大小线程池的工作流程

固定大小线程池使用无界队列(LinkedBlockingQueue)作为工作队列,其核心特点包括:

  • 当核心线程未满时:立即创建新的核心线程执行任务。
  • 当核心线程已满时:将新的任务 enqueu到队列中,等待核心线程空闲。
  • 任务从队列中获取:核心线程会一直从队列中获取任务执行,直到队列为空。
  • 示例代码

    class MyTask implements Runnable {    private int taskNum;    public MyTask(int num) {        this.taskNum = num;    }    @Override    public void run() {        System.out.println("Thread " + Thread.currentThread().getName() + "正在执行任务 " + taskNum);        try {            Thread.sleep(1000); // 模拟耗时任务        } catch (InterruptedException e) {            e.printStackTrace();        }        System.out.println("Thread " + Thread.currentThread().getName() + "完成执行任务 " + taskNum);    }}public class Demo {    public static void main(String[] args) {        ExecutorService executor = Executors.newFixedThreadPool(3); // 创建3个核心线程        for (int i = 0; i < 6; i++) {            executor.execute(new MyTask(i));        }        executor.shutdown();    }}

    运行结果说明:

    • 线程池初始创建3个核心线程。
    • 新任务被 enqueu至队列,核心线程逐一处理。
    • 每个任务执行完成后会Log结果。

    四、单个线程池的工作流程

    单个线程池与固定大小线程池的区别主要在于:

    • 只有一个核心线程处理所有任务。
    • 任务会按顺序执行,缺少并行性。

    示例代码

    class MyTask implements Runnable {    private int taskNum;    public MyTask(int num) {        this.taskNum = num;    }    @Override    public void run() {        System.out.println("Thread " + Thread.currentThread().getName() + "正在执行任务 " + taskNum);        try {            Thread.sleep(1000); // 模拟耗时任务        } catch (InterruptedException e) {            e.printStackTrace();        }        System.out.println("Thread " + Thread.currentThread().getName() + "完成执行任务 " + taskNum);    }}public class Demo {    public static void main(String[] args) {        ExecutorService executor = Executors.newSingleThreadExecutor();        for (int i = 0; i < 6; i++) {            executor.execute(new MyTask(i));        }        executor.shutdown();    }}

    运行结果说明:

    • 只有一个线程负责执行所有任务。
    • 任务按顺序依次处理,结果输出也是按照任务提交顺序出现。

    五、定时线程池的应用场景

    定时线程池适合需要在特定时间间隔触发任务执行的情景。例如发送定时邮件、定期检查系统状态等。

    使用方法

    ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();executor.scheduleWithFixedDelay(new Runnable(), initialDelay, delay, TimeUnit.SECONDS);

    其中 initialDelay 表示第一次执行的延迟,delay 表示后续任务的固定执行间隔。

    示例代码

    import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.TimeUnit;class MyTask implements Runnable {    private int taskNum;    public MyTask(int num) {        this.taskNum = num;    }    @Override    public void run() {        try {            System.out.println("Thread " + Thread.currentThread().getName() + "正在执行任务 " + taskNum);            Thread.sleep(1000); // 模拟耗时任务        } catch (InterruptedException e) {            e.printStackTrace();        }        System.out.println("Thread " + Thread.currentThread().getName() + "完成执行任务 " + taskNum);    }}public class Demo {    public static void main(String[] args) {        ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();        executor.scheduleWithFixedDelay(new MyTask(), 0, 3, TimeUnit.SECONDS); // 每隔3秒执行一次        executor.shutdown();    }}

    运行结果说明:

    • 每隔3秒,线程池中创建一个新任务,按照预定的间隔执行任务。
    • 如果任务执行耗时较长,任务调度也会继续,第二个任务将在第4秒开始执行。

    六、缓存线程池的优势

    缓存线程池的核心特点是支持动态创建和回收线程,适合任务负载波动较大的场景。其最大池大小为 Integer.MAX_VALUE,超出核心线程数的空闲线程会在60秒内若无新任务提交则终止。

    使用方法

    ThreadPoolExecutor executor = new ThreadPoolExecutor(    0,     Integer.MAX_VALUE,     60,     TimeUnit.SECONDS,     new SynchronousQueue<>());

    示例代码

    import java.util.concurrent.ThreadPoolExecutor;import java.util.concurrent.TimeUnit;class MyTask implements Runnable {    private int taskNum;    public MyTask(int num) {        this.taskNum = num;    }    @Override    public void run() {        System.out.println("Thread " + Thread.currentThread().getName() + "正在执行任务 " + taskNum);        try {            Thread.sleep(1000); // 模拟耗时任务        } catch (InterruptedException e) {            e.printStackTrace();        }        System.out.println("Thread " + Thread.currentThread().getName() + "完成执行任务 " + taskNum);    }}public class Demo {    public static void main(String[] args) {        ThreadPoolExecutor executor = new ThreadPoolExecutor(            0, // corePoolSize            Integer.MAX_VALUE, // maximumPoolSize            60, // keepAliveTime            TimeUnit.SECONDS, // time unit            new SynchronousQueue<>() // work queue        );        for (int i = 0; i < 10; i++) {            executor.execute(new MyTask(i));        }        executor.shutdown();    }}

    运行结果说明:

    • 缓存线程池根据任务需求自动扩展和收缩线程数量,能最大化资源利用率。
    • 空闲线程将在60秒内若无新任务则终止,避免资源浪费。

    总结

    线程池是Java中处理并发任务的重要工具,其中固定大小、单个、定时和缓存线程池各有特点。选择合适的线程池类型,能够有效地优化程序性能和资源利用率。在实际开发中,根据任务的特性和负载情况,合理使用线程池,使程序更加高效和健壮。

    转载地址:http://futjz.baihongyu.com/

    你可能感兴趣的文章
    nullnullHuge Pages
    查看>>
    Numpy如何使用np.umprod重写range函数中i的python
    查看>>
    oauth2-shiro 添加 redis 实现版本
    查看>>
    OAuth2.0_JWT令牌-生成令牌和校验令牌_Spring Security OAuth2.0认证授权---springcloud工作笔记148
    查看>>
    OAuth2.0_JWT令牌介绍_Spring Security OAuth2.0认证授权---springcloud工作笔记147
    查看>>
    OAuth2.0_介绍_Spring Security OAuth2.0认证授权---springcloud工作笔记137
    查看>>
    OAuth2.0_完善环境配置_把资源微服务客户端信息_授权码存入到数据库_Spring Security OAuth2.0认证授权---springcloud工作笔记149
    查看>>
    OAuth2.0_授权服务配置_Spring Security OAuth2.0认证授权---springcloud工作笔记140
    查看>>
    OAuth2.0_授权服务配置_客户端详情配置_Spring Security OAuth2.0认证授权---springcloud工作笔记142
    查看>>
    OAuth2.0_授权服务配置_密码模式及其他模式_Spring Security OAuth2.0认证授权---springcloud工作笔记145
    查看>>
    OAuth2.0_授权服务配置_资源服务测试_Spring Security OAuth2.0认证授权---springcloud工作笔记146
    查看>>
    OAuth2.0_环境介绍_授权服务和资源服务_Spring Security OAuth2.0认证授权---springcloud工作笔记138
    查看>>
    OAuth2.0_环境搭建_Spring Security OAuth2.0认证授权---springcloud工作笔记139
    查看>>
    OA系统多少钱?OA办公系统中的价格选型
    查看>>
    Object c将一个double值转换为时间格式
    查看>>
    object detection错误之Could not create cudnn handle: CUDNN_STATUS_INTERNAL_ERROR
    查看>>
    Object of type 'ndarray' is not JSON serializable
    查看>>
    Object Oriented Programming in JavaScript
    查看>>
    OBJECTIVE C (XCODE) 绘图功能简介(转载)
    查看>>
    Objective-C——判断对象等同性
    查看>>