Java一分钟之线程池:ExecutorService与Future

本文涉及的产品
智能开放搜索 OpenSearch行业算法版,1GB 20LCU 1个月
实时数仓Hologres,5000CU*H 100GB 3个月
实时计算 Flink 版,5000CU*H 3个月
简介: 【5月更文挑战第12天】Java并发编程中,`ExecutorService`和`Future`是关键组件,简化多线程并提供异步执行能力。`ExecutorService`是线程池接口,用于提交任务到线程池,如`ThreadPoolExecutor`和`ScheduledThreadPoolExecutor`。通过`submit()`提交任务并返回`Future`对象,可检查任务状态、获取结果或取消任务。注意处理`ExecutionException`和避免无限等待。实战示例展示了如何异步执行任务并获取结果。理解这些概念对提升并发性能至关重要。

在Java并发编程的世界里,线程池是提高程序性能、管理线程生命周期的利器。ExecutorServiceFuture作为Java并发包中的核心组件,它们不仅简化了多线程编程的复杂度,还为我们提供了强大的异步执行和结果获取能力。本文将深入浅出地探讨这两个概念,揭示常见问题、易错点及避免策略,并辅以代码示例,帮助大家更好地理解和应用。
image.png

ExecutorService:线程池的指挥官

简介

ExecutorServicejava.util.concurrent包下的接口,它是线程池的主接口,提供了执行任务的高级接口。通过它,我们可以提交任务(Runnable或Callable类型)到线程池中执行,而无需关心线程的创建、调度和销毁等细节。

常见实现类

  • ThreadPoolExecutor:最常用的线程池实现,提供了高度可配置的线程池参数,如核心线程数、最大线程数、线程存活时间等。
  • ScheduledThreadPoolExecutor:支持定时及周期性任务执行的线程池。

创建线程池

ExecutorService executor = Executors.newFixedThreadPool(10); // 创建固定大小线程池

提交任务

executor.submit(() -> System.out.println("Running task in thread pool."));

关闭线程池

executor.shutdown(); // 平缓关闭,不再接受新任务,等待现有任务完成
// 或者
executor.shutdownNow(); // 立即关闭,尝试中断正在执行的任务

Future:异步任务的未来

简介

当你通过submit(Callable<T> task)方法向ExecutorService提交一个Callable任务时,返回的是一个Future<T>对象。这个Future代表了异步计算的结果,提供了检查计算是否完成、获取计算结果以及取消计算的方法。

常用方法

  • isDone(): 判断任务是否已完成。
  • get(): 阻塞等待直到任务完成并返回结果,可能会抛出异常。
  • get(long timeout, TimeUnit unit): 在指定时间内等待任务完成。
  • cancel(boolean mayInterruptIfRunning): 尝试取消任务,如果任务已经开始执行且mayInterruptIfRunning为true,则尝试中断执行。

易错点与避免策略

易错点1:忽视异常处理

Callable任务中抛出的异常会被封装进ExecutionException,调用Future.get()时必须妥善处理这一异常。

避免策略

try {
   
   
    String result = future.get();
} catch (InterruptedException e) {
   
   
    Thread.currentThread().interrupt(); // 重新设置中断标志
    // 处理中断
} catch (ExecutionException e) {
   
   
    // 处理任务执行时抛出的异常
    Throwable cause = e.getCause();
    // ...
}

易错点2:无限等待

使用get()方法时,如果没有设置超时,程序可能会因为等待任务完成而无限阻塞。

避免策略

总是考虑使用带超时参数的get(long timeout, TimeUnit unit)方法,或者在合适的时机检查isDone()状态。

实战示例:异步任务与结果获取

import java.util.concurrent.*;

public class ExecutorServiceFutureDemo {
   
   

    public static void main(String[] args) throws ExecutionException, InterruptedException {
   
   
        ExecutorService executor = Executors.newFixedThreadPool(1);

        Future<Integer> future = executor.submit(() -> {
   
   
            Thread.sleep(2000); // 模拟耗时操作
            return 42; // 计算结果
        });

        System.out.println("Task submitted, doing something else...");

        // 非阻塞方式检查结果
        while (!future.isDone()) {
   
   
            System.out.println("Task is not done yet...");
            Thread.sleep(500);
        }

        // 获取结果
        System.out.println("Result: " + future.get());

        executor.shutdown();
    }
}

结语

通过ExecutorServiceFuture,Java为我们提供了一套强大且灵活的并发编程工具集。理解它们的工作原理、掌握常见的使用技巧及避免常见陷阱,对于提升程序的并发性能和稳定性至关重要。希望本文能帮助你更深入地掌握这两项技术,让你在编写高效并发程序的道路上更进一步。

目录
相关文章
|
14天前
|
监控 Java
java异步判断线程池所有任务是否执行完
通过上述步骤,您可以在Java中实现异步判断线程池所有任务是否执行完毕。这种方法使用了 `CompletionService`来监控任务的完成情况,并通过一个独立线程异步检查所有任务的执行状态。这种设计不仅简洁高效,还能确保在大量任务处理时程序的稳定性和可维护性。希望本文能为您的开发工作提供实用的指导和帮助。
68 17
|
25天前
|
Java
Java—多线程实现生产消费者
本文介绍了多线程实现生产消费者模式的三个版本。Version1包含四个类:`Producer`(生产者)、`Consumer`(消费者)、`Resource`(公共资源)和`TestMain`(测试类)。通过`synchronized`和`wait/notify`机制控制线程同步,但存在多个生产者或消费者时可能出现多次生产和消费的问题。 Version2将`if`改为`while`,解决了多次生产和消费的问题,但仍可能因`notify()`随机唤醒线程而导致死锁。因此,引入了`notifyAll()`来唤醒所有等待线程,但这会带来性能问题。
Java—多线程实现生产消费者
|
10天前
|
缓存 安全 算法
Java 多线程 面试题
Java 多线程 相关基础面试题
|
27天前
|
安全 Java Kotlin
Java多线程——synchronized、volatile 保障可见性
Java多线程中,`synchronized` 和 `volatile` 关键字用于保障可见性。`synchronized` 保证原子性、可见性和有序性,通过锁机制确保线程安全;`volatile` 仅保证可见性和有序性,不保证原子性。代码示例展示了如何使用 `synchronized` 和 `volatile` 解决主线程无法感知子线程修改共享变量的问题。总结:`volatile` 确保不同线程对共享变量操作的可见性,使一个线程修改后,其他线程能立即看到最新值。
|
27天前
|
消息中间件 缓存 安全
Java多线程是什么
Java多线程简介:本文介绍了Java中常见的线程池类型,包括`newCachedThreadPool`(适用于短期异步任务)、`newFixedThreadPool`(适用于固定数量的长期任务)、`newScheduledThreadPool`(支持定时和周期性任务)以及`newSingleThreadExecutor`(保证任务顺序执行)。同时,文章还讲解了Java中的锁机制,如`synchronized`关键字、CAS操作及其实现方式,并详细描述了可重入锁`ReentrantLock`和读写锁`ReadWriteLock`的工作原理与应用场景。
|
27天前
|
安全 Java 编译器
深入理解Java中synchronized三种使用方式:助您写出线程安全的代码
`synchronized` 是 Java 中的关键字,用于实现线程同步,确保多个线程互斥访问共享资源。它通过内置的监视器锁机制,防止多个线程同时执行被 `synchronized` 修饰的方法或代码块。`synchronized` 可以修饰非静态方法、静态方法和代码块,分别锁定实例对象、类对象或指定的对象。其底层原理基于 JVM 的指令和对象的监视器,JDK 1.6 后引入了偏向锁、轻量级锁等优化措施,提高了性能。
53 3
|
8月前
|
Java 调度
Java并发编程:深入理解线程池的原理与实践
【4月更文挑战第6天】本文将深入探讨Java并发编程中的重要概念——线程池。我们将从线程池的基本原理入手,逐步解析其工作过程,以及如何在实际开发中合理使用线程池以提高程序性能。同时,我们还将关注线程池的一些高级特性,如自定义线程工厂、拒绝策略等,以帮助读者更好地掌握线程池的使用技巧。
|
5月前
|
安全 Java 数据库
一天十道Java面试题----第四天(线程池复用的原理------>spring事务的实现方式原理以及隔离级别)
这篇文章是关于Java面试题的笔记,涵盖了线程池复用原理、Spring框架基础、AOP和IOC概念、Bean生命周期和作用域、单例Bean的线程安全性、Spring中使用的设计模式、以及Spring事务的实现方式和隔离级别等知识点。
|
4月前
|
存储 缓存 Java
JAVA并发编程系列(11)线程池底层原理架构剖析
本文详细解析了Java线程池的核心参数及其意义,包括核心线程数量(corePoolSize)、最大线程数量(maximumPoolSize)、线程空闲时间(keepAliveTime)、任务存储队列(workQueue)、线程工厂(threadFactory)及拒绝策略(handler)。此外,还介绍了四种常见的线程池:可缓存线程池(newCachedThreadPool)、定时调度线程池(newScheduledThreadPool)、单线程池(newSingleThreadExecutor)及固定长度线程池(newFixedThreadPool)。
|
6月前
|
监控 Java 开发者
深入理解Java并发编程:线程池的原理与实践
【5月更文挑战第85天】 在现代Java应用开发中,高效地处理并发任务是提升性能和响应能力的关键。线程池作为一种管理线程的机制,其合理使用能够显著减少资源消耗并优化系统吞吐量。本文将详细探讨线程池的核心原理,包括其内部工作机制、优势以及如何在Java中正确实现和使用线程池。通过理论分析和实例演示,我们将揭示线程池对提升Java应用性能的重要性,并给出实践中的最佳策略。