Java学习——day28(Java并发工具类与线程池)

1. 并发工具类简介

1.1 ExecutorService

  • 作用:
    ExecutorService 是 Java 并发包中一个用于管理线程池的接口,封装了线程的创建、执行和销毁过程。
  • 特点:
    1.能动态分配线程资源;
    2.能安排任务的执行,并且支持有返回结果的任务;
    3.提供 shutdown()/shutdownNow() 方法用于平滑关闭线程池。

1.2 Callable 和 Future

  • Callable 接口:
    与 Runnable 接口类似,不同点在于 Callable 可以返回任务执行结果,并且可以抛出异常。其定义一个泛型方法 call()
  • Future 接口:
    Future 表示异步计算的结果,提供了方法来检查任务是否完成、获取结果以及取消任务等。
    • 通过get()方法可以阻塞等待任务完成并返回结果。
    • 通过 cancel() 方法可以取消任务执行。

1.3 Executors 工具类

  • 作用:
    Executors 是一个工具类,提供了一系列静态方法简化线程池的创建,如:
    • Executors.newFixedThreadPool(n):创建一个固定大小的线程池。
    • Executors.newCachedThreadPool():创建一个可缓存的线程池,适合执行大量短生命周期任务。
    • Executors.newSingleThreadExecutor():创建一个只有一个线程的线程池,按顺序执行任务。

1.4 线程池优势

  • 资源复用:线程池维护一定数量的线程,可重复利用这些线程,避免了频繁创建和销毁线程带来的开销。
  • 任务调度:线程池内部提供任务队列管理,支持任务的延迟执行和周期性执行。
  • 更好的控制:可通过线程池参数控制线程的最大并发数、任务等待队列大小,从而有效管理系统资源并避免系统过载。

2. 实践:线程池执行任务并收集结果示例

接下来我们编写一个示例程序。程序步骤如下:
1.创建一个固定大小的线程池(例如 3 个线程)。
2.提交一组 Callable 任务,每个任务返回一个计算结果(比如对任务编号进行简单运算或拼接字符串)。
3.使用 Future 收集任务的返回结果。
4.输出任务的执行结果。
5.最后平滑地关闭线程池。

2.1 示例代码

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class ThreadPoolExample {

    public static void main(String[] args) {
        // 1. 创建固定大小为3的线程池
        ExecutorService executor = Executors.newFixedThreadPool(3);
        
        // 2. 创建一个任务列表(Callable任务)
        List<Callable<String>> taskList = new ArrayList<>();
        
        // 假设我们提交5个任务,每个任务返回一个字符串结果
        for (int i = 1; i <= 5; i++) {
            final int taskId = i;
            taskList.add(new Callable<String>() {
                @Override
                public String call() throws Exception {
                    // 模拟任务耗时
                    Thread.sleep(500);
                    return "任务 " + taskId + " 执行完毕";
                }
            });
        }
        
        try {
            // 3. 执行所有任务,并返回一个包含 Future 对象的列表
            List<Future<String>> futureList = executor.invokeAll(taskList);
            
            // 4. 逐个获取任务返回结果(Future.get()会阻塞直到任务完成)
            for (Future<String> future : futureList) {
                try {
                    String result = future.get();
                    System.out.println("任务返回结果:" + result);
                } catch (InterruptedException | ExecutionException e) {
                    System.err.println("任务执行异常:" + e.getMessage());
                }
            }
        } catch (InterruptedException e) {
            System.err.println("任务提交过程中被中断:" + e.getMessage());
        } finally {
            // 5. 关闭线程池
            executor.shutdown();
        }
    }
}

3. 代码详解

3.1 线程池的创建

ExecutorService executor = Executors.newFixedThreadPool(3);
  • 使用 Executors.newFixedThreadPool(3) 创建一个固定大小为 3 的线程池。这样,线程池中最多同时运行 3 个线程。

3.2 定义任务列表

List<Callable<String>> taskList = new ArrayList<>();
  • 使用 Callable<String> 表明任务返回的是一个 String 类型的结果。
  • 循环提交 5 个任务,每个任务模拟了 500 毫秒的工作,并返回 “任务 i 执行完毕”。

3.3 提交任务并收集 Future

List<Future<String>> futureList = executor.invokeAll(taskList);
  • invokeAll 方法接受任务列表,并一次性提交所有任务到线程池中,会阻塞直到所有任务完成。
  • 返回一个 Future 列表,未来可以用来获取每个任务的执行结果。

3.4 获取任务执行结果

for (Future<String> future : futureList) {
    String result = future.get();
    System.out.println("任务返回结果:" + result);
}
  • 遍历 Future 列表,对于每个任务调用 future.get(),该方法会阻塞直到任务完成并返回结果。
  • 输出结果显示每个任务的返回字符串。

3.5 关闭线程池

executor.shutdown();
  • 调用 shutdown() 方法,线程池不再接受新的任务,并等待已提交的任务执行完毕后关闭。

4. 编译与运行结果

4.1 编译

在你的 IDE(如 IntelliJ IDEA)中创建一个 Java 类 ThreadPoolExample.java,粘贴上述代码,然后编译整个项目。

4.2 运行结果

运行程序后,控制台的输出类似如下:

任务返回结果:任务 1 执行完毕
任务返回结果:任务 2 执行完毕
任务返回结果:任务 3 执行完毕
任务返回结果:任务 4 执行完毕
任务返回结果:任务 5 执行完毕

说明:

  • 输出结果的顺序可能与任务提交的顺序一致,因为invokeAll会按照任务列表顺序返回 Future,即使内部任务并发运行,因为它等待所有任务完成后才返回。
  • 每个任务的执行结果是由任务内部返回字符串确定的,模拟了耗时计算,并验证了线程池任务的并行处理能力。

5. 总结

  • ExecutorService 与线程池:
    使用线程池可以避免频繁创建和销毁线程,通过合理配置线程池大小来复用线程,提高性能并控制资源使用。
  • Callable 与 Future:
    Callable 能返回结果,Future 用来获取这些结果和检测任务状态,是执行有返回结果任务的首选方式。
  • 使用 Executors 创建线程池:
    Executors 工具类提供了多种线程池创建方式,简单方便地管理并发任务执行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值