首页 > 其他分享 >线程管理神器:Executors全面解析

线程管理神器:Executors全面解析

时间:2024-01-24 14:37:46浏览次数:32  
标签:java Executors 创建 神器 任务 线程 执行

线程管理神器:Executors全面解析- 程序员古德

内容摘要

Executors在Java中提供了快速创建线程池的能力,其优点显著:它简化了线程管理,减少了代码量;提供了多种类型的线程池以适应不同场景;通过复用线程,降低了资源消耗,提高了系统响应速度和吞吐量。使用Executors,开发者能够更专注于业务逻辑,而无需深入底层线程细节。

官方文档:https://docx.iamqiang.com/jdk11/api/java.base/java/util/concurrent/Executors.html

核心概念

在Java中,Executors 是一个提供线程池功能的实用工具类,它允许更便捷地创建、管理和控制线程,从而优化资源使用和提高系统性能。

模拟一个例子,假如有一个公司的电商平台即将开始双十一大促互动,大促活动预计将带来前所未有的流量和订单量,在这种情况下,为了确保系统的稳定性和高效性,不能简单地为每个用户请求都创建一个新线程来处理,因为这样做会消耗大量系统资源,并且可能导致服务器崩溃,这是可以使用Executors

可以将Executors想象成一家高效的物流公司,当电商平台接收到用户订单时(就像物流公司接收到货物一样),不是直接为每个订单派一辆独立的货车去送货(这相当于为每个请求创建一个新线程),而是将这些订单放入一个集中的处理中心(线程池)。

这个处理中心(线程池)由Executors管理,它会根据当前的订单量(任务量)和系统资源情况,智能地分配有限的货车(线程)去送货(执行任务),如果订单量激增,Executors会自动排队并管理这些订单,确保每个订单都能得到及时处理,同时避免资源的浪费和系统的崩溃。

使用Executors可以更高效地管理线程,特别是在处理大量并发任务时,它能够显著提升系统的性能和稳定性。

代码案例

如下是一个Executors的使用案例,展示了用一个固定大小的线程池来并发执行任务,如下代码:

import java.util.concurrent.ExecutorService;  
import java.util.concurrent.Executors;  
import java.util.concurrent.TimeUnit;  
  
public class ThreadPoolExample {  
  
    public static void main(String[] args) {  
        // 创建一个固定大小的线程池,其中包含了3个线程  
        ExecutorService executorService = Executors.newFixedThreadPool(3);  
  
        // 提交10个任务到线程池  
        for (int i = 0; i < 10; i++) {  
            final int taskId = i;  
            executorService.submit(() -> {  
                // 模拟任务执行,这里简单地打印任务ID和执行的线程名  
                System.out.println("Executing task " + taskId + " via " + Thread.currentThread().getName());  
                try {  
                    // 让线程休眠一段时间,模拟任务耗时  
                    Thread.sleep(1000);  
                } catch (InterruptedException e) {  
                    // 如果线程被中断,则处理中断  
                    e.printStackTrace();  
                }  
            });  
        }  
  
        // 关闭线程池(这会让线程池不再接受新的任务,但会继续处理队列中的任务)  
        executorService.shutdown();  
  
        // 等待所有任务完成(这里等待的时间比所有任务的总执行时间要长,以确保所有任务都能完成)  
        try {  
            if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {  
                // 如果等待超时后线程池仍未关闭,可以选择执行一些额外的操作,比如取消剩余任务  
                System.err.println("Not all tasks finished in the given time.");  
            }  
        } catch (InterruptedException ie) {  
            // 如果当前线程在等待过程中被中断,则处理中断  
            System.err.println("Interrupted while waiting for tasks to complete.");  
            // 重新设置中断状态,以便调用者能够知道发生了中断  
            Thread.currentThread().interrupt();  
        }  
  
        System.out.println("All tasks are finished.");  
    }  
}

在上面代码中,通过Executors.newFixedThreadPool(3)创建了一个包含3个线程的线程池,然后提交了10个任务到线程池,每个任务都简单地打印出任务ID和执行它的线程名,然后休眠1秒钟来模拟任务执行。

这里实例中的代码是非常简单的,并且只是为了演示线程池的基本用法,在实际应用中,可能会有更复杂和耗时的任务需要处理。

核心API说明

Executors 是 Java 并发库 java.util.concurrent 中的一个实用类,用于创建和管理各种线程池和 ExecutorService,该类提供了多个工厂方法来创建不同类型的 ExecutorService,以下是一些常用的 Executors 方法及其含义:

  1. newFixedThreadPool(int nThreads):创建一个固定大小的线程池,该线程池中的线程数量始终保持不变,如果所有线程都在执行任务并且又有新任务提交,那么新任务会进入队列等待,直到有线程空闲出来,如果线程因为异常结束,那么会有新的线程来替代它。
  2. newCachedThreadPool():创建一个可缓存的线程池,如果线程池的大小超过了处理需求,那么会回收空闲线程(60秒无任务的线程),当提交新任务时,如果没有空闲线程,那么会创建新的线程,该线程池的大小可以动态调整。
  3. newSingleThreadExecutor():创建一个单线程的 ExecutorService,所有提交的任务都会按照这个顺序在一个线程中执行,如果该线程因为异常结束,那么会有新的线程来替代它。
  4. newSingleThreadScheduledExecutor():创建一个单线程的 ScheduledExecutorService,该线程池可以调度在给定的延迟后执行命令,或者定期执行命令。
  5. newScheduledThreadPool(int corePoolSize):创建一个可以调度在给定的延迟后执行命令,或者定期执行命令的线程池,该线程池的核心线程数量是固定的,但非核心线程数量可以动态调整(基于工作队列的大小和任务提交的速度)。

注意:尽管 Executors 提供了方便的工厂方法来创建线程池,但在生产环境中,建议使用 ThreadPoolExecutor 的直接构造方法来创建线程池,这样可以更细粒度地控制线程池的参数和配置。

另外,从Java 9开始,Executors 类中增加了 newWorkStealingPool 方法,用于创建一个工作窃取线程池,这在处理大量并行任务时非常有用,特别是当任务的执行时间不确定时。工作窃取算法可以帮助平衡各个线程之间的工作量,从而提高整体的吞吐量。

核心总结

线程管理神器:Executors全面解析 - 程序员古德

Executors是Java中创建线程池的便捷工具,其优点在于提供了多种类型的线程池以满足不同场景的需求,如固定大小、缓存、单线程等,这些线程池减少了资源管理的复杂性,并提供了性能优势,然而,Executors的缺点在于其默认配置可能不适合所有场景,如工作队列大小和拒绝策略等,在复杂场景中,优先考虑使用ThreadPoolExecutor以获得更多的线程控制权。

关注我,每天学习互联网编程技术 - 程序员古德

END!

标签:java,Executors,创建,神器,任务,线程,执行
From: https://blog.51cto.com/bytegood/9395388

相关文章

  • python多线程id获取
    demoimportthreadingimporttimedefprint_thread_info(thread_name):"""线程函数,打印线程名称和ID以及一些文本"""foriinrange(3):time.sleep(1)thread_id=threading.current_thread().identprint(f"{thr......
  • 【面试突击】并发编程、线程池面试实战
    欢迎关注公众号(通过文章导读关注:【11来了】),及时收到AI前沿项目工具及新技术的推送!在我后台回复「资料」可领取编程高频电子书!在我后台回复「面试」可领取硬核面试笔记!前言最近在更新面试突击专栏,我把每一篇将字数都尽量控制在2000字以内,可能在文章里边写的没有那么细致,主要是......
  • 并发编程之多线程
    多线程1.什么是线程就是一条流水线工作的过程,一条流水线必须属于一个车间,一个车间的工作过程是一个进程车间负责把资源整合到一起,是一个资源单位,而一个车间内至少有一个流水线流水线的工作需要电源,电源就相当于cpu所以,进程只是用来把资源集中到一起(进程只是一个资源单位,或者......
  • C# 线程本地存储 为什么线程间值不一样
    一:背景1.讲故事有朋友在微信里面问我,为什么用ThreadStatic标记的字段,只有第一个线程拿到了初始值,其他线程都是默认值,让我能不能帮他解答一下,尼玛,我也不是神仙什么都懂,既然问了,那我试着帮他解答一下,也给后面类似疑问的朋友解个惑吧。二:为什么值不一样1.问题复现为了方便讲......
  • 【6.2】线程的互斥锁
    【一】问题所有子线程都会进行阻塞操作,导致最后的改变只是改了一次fromthreadingimportThreadimporttimemoney=100deftask():globalmoney#模拟获取到车票信息temp=money#模拟网络延迟time.sleep(2)#模拟购票money=......
  • 【11.0】进程池和线程池
    【一】TCP实现并发的效果的原理每开设一个客户端,就会有一个服务端服务【1】服务端fromsocketimport*fromthreadingimportThreaddefserver_create(IP,PORT):server=socket()server.bind((IP,PORT))server.listen(5)whileTrue:......
  • 【10.0】线程queue
    【零】队列queue介绍queue队列:使用importqueue,用法与进程Queue一样queueisespeciallyusefulinthreadedprogrammingwheninformationmustbeexchangedsafelybetweenmultiplethreads.classqueue.Queue(maxsize=0)先进先出importqueueq=queue.Queue()......
  • 线程同步之信号量
    目录Semaphore信号量Semaphore与condition_variable的区别Semaphore信号量在C++中,可以使用std::Semaphore类来实现信号量。信号量可以用于控制对资源的访问,例如限制同时执行任务的线程数量。在C++11中,std::Semaphore类提供了以下常用函数:Semaphore():构造函数,创建一个信......
  • MySQL线程状态详解
    前言:我们常用showprocesslist或showfullprocesslist查看数据库连接状态,其中比较关注的是State列,此列表示该连接此刻所在的状态。那么你真的了解不同State值所表示的状态吗?下面我们参考官方文档来一探究竟。以MySQL5.7版本为例官方文档地址:https://dev.my......
  • QT笔记:多线程和信号槽
    QT笔记:多线程和信号槽多线程创建多线程有两种方法,一般推荐用moveToThread方法参考代码如下:mainwindow.h#ifndefMAINWINDOW_H#defineMAINWINDOW_H#include<QMainWindow>#include<QApplication>QT_BEGIN_NAMESPACEnamespaceUi{classMainWindow;}QT_END_NAMES......