Java多线程 线程池Executor框架

简介: Java多线程 线程池Executor框架

一、说明


线程池的引出


  • 通过new语句创建一个Java对象时,JVM就会为这个对象分配一块内存空间


  • 而线程的创建和销毁需要调用操作系统内核的API,成本较高


  • 线程池是一个容纳多个线程的容器,通过复用线程来达到执行多个任务的目的,对线程进行统一的分配,调优和监控,无需重复创建线程,优化了资源开销,由此引出Executor框架


二、理解


Executor


  • java.util.cocurrent 包下Executor接口,内部使用线程池机制,控制线程的启动、执行和关闭,相比Thread.start()方法效率更高,易于管理


包括三大部分


  • 任务:被执行任务需要实现CallableRunnable接口


  • 任务的执行:把任务分派给多个线程的执行机制, ExecutorExecutorService接口及其实现类


  • 异步计算的结果: Future 接口 FutureTask实现类



  • Executor即线程池接口,其execute()方法接收Runnable接口的对象,但没有返回结果


  • ExecutorService 接口用来实现和管理多线程,提供生命周期管理方法,返回 Future 对象,当所有已经提交的任务执行完毕后将会关闭该接口


  • AbstractExecutorService 类用来提供线程接口的一些默认实现


  • ThreadPoolExecutor 线程池的实现类,通过调用Executors创建线程池并返回一个ExecutorService对象


  • ScheduledExecutorService 接口用来执行定时任务


  • ScheduledThreadPoolExecutor 用来调度定时任务的线程池实现类


Executor框架使用流程



ExecutorService


  • 继承 Executor 接口


  • submit()方法接收RunnableCallable接口的对象,有返回执行结果的对象


  • 关闭线程池调用 shutDown() 方法停止接收新任务,原来的任务继续执行;或者shutdownNow()方法停止接收新任务,原来的任务停止执行


Executors


  • 线程池工厂类,提供生成Executor(线程池)的方法,返回的线程池都实现了ExecutorService接口


  • newSingleThreadExecutor() 创建单个线程的线程池


  • newFixedThreadPool(int numOfThreads) 创建固定线程数的线程池,可控制线程最大并发数,超出的线程会在队列中等待


  • newCachedThreadPool() 根据需要创建新的线程,自动回收空闲线程,所有线程都会在限制60秒后被回收,如果回收后又创建了任务,将新创建一个线程


  • newScheduledThreadPool(int) 创建一个支持定时及周期性执行任务的线程池


三、实现


1. newSingleThreadExecutor


创建一个SingThreadExecutorTest类,单个线程的线程池执行MyThread1MyThread2任务


public class SingThreadExecutorTest {
    public static void main(String[] args) {
        // 1.创建一个单线程化的线程池
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        // 2.创建10次线程任务
        for (int i = 0; i < 5; i++) {
            // 3.执行线程任务
            executorService.execute(new MyThread1());
            executorService.execute(new MyThread2());
        }
        // 4.关闭线程池
        executorService.shutdown();
    }
    static class MyThread1 extends Thread {
        @Override
        public void run() {
            try {
                System.out.println(Thread.currentThread().getName() + "        我是任务1");
                sleep(2000);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    static class MyThread2 extends Thread {
        @Override
        public void run() {
            try {
                System.out.println(Thread.currentThread().getName() + " 我是任务2");
                sleep(2000);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}


只有单个线程池去执行10个任务



2. newFixedThreadPool


创建固定线程数的线程池,可控制线程最大并发数,超出的线程会在队列中等待


    public static void main(String[] args) {
        // 1.创建容量为5线程数的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        // 2.创建10次线程任务
        for (int i = 0; i < 5; i++) {
            // 3.执行线程任务
            executorService.execute(new MyThread1());
            executorService.execute(new MyThread2());
        }
        // 4.关闭线程池
        executorService.shutdown();
    }


5个线程去执行10个任务



3. newCachedThreadPool


根据需要创建新的线程,自动回收空闲线程,所有线程都会在限制60秒后被回收,如果回收后又创建了任务,将新创建一个线程


    public static void main(String[] args) {
        // 1.创建可缓存的线程池
        ExecutorService executorService = Executors.newCachedThreadPool();
        // 2.创建10次线程任务
        for (int i = 0; i < 5; i++) {
            // 3.执行线程任务
            executorService.execute(new MyThread1());
            executorService.execute(new MyThread2());
        }
        // 4.关闭线程池
        executorService.shutdown();
    }


根据需要自动创建新线程去只执行10个任务



当线程运行时间超过60秒时


    public static void main(String[] args) throws InterruptedException {
        // 1.创建可缓存的线程池
        ExecutorService executorService = Executors.newCachedThreadPool();
        // 2.创建线程任务执行
        for (int i = 0; i < 5; i++) {
            executorService.execute(new MyThread1());
        }
        Thread.sleep(30000);
        System.out.println("睡眠30秒");
        for (int i = 0; i < 5; i++) {
            executorService.execute(new MyThread1());
        }
        Thread.sleep(65000);
        System.out.println("睡眠65秒");
        for (int i = 0; i < 5; i++) {
            executorService.execute(new MyThread1());
        }
        // 4.关闭线程池
        executorService.shutdown();
    }


5个线程执行任务再休眠30秒后,线程并未被回收,继续用这5个线程执行任务,休眠65秒后,线程被回收,新建5个线程执行任务



4. newScheduledThreadPool


创建一个支持定时及周期性执行任务的线程池


public class SingThreadExecutorTest {
    public static void main(String[] args) {
        // 1.创建容量为5线程数的线程池
        ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5);
        // 2.创建10次线程任务
        for (int i = 0; i < 5; i++) {
            // 3.执行线程任务
            executorService.schedule(new MyThread1(),5000 , TimeUnit.MILLISECONDS);
            executorService.schedule(new MyThread2(),1000 , TimeUnit.MILLISECONDS);
        }


5个线程去执行10个任务,任务2马上就执行完成了,而任务1要延迟5秒才执行完成


目录
相关文章
|
23天前
|
存储 安全 Java
Java 集合框架中的老炮与新秀:HashTable 和 HashMap 谁更胜一筹?
嗨,大家好,我是技术伙伴小米。今天通过讲故事的方式,详细介绍 Java 中 HashMap 和 HashTable 的区别。从版本、线程安全、null 值支持、性能及迭代器行为等方面对比,帮助你轻松应对面试中的经典问题。HashMap 更高效灵活,适合单线程或需手动处理线程安全的场景;HashTable 较古老,线程安全但性能不佳。现代项目推荐使用 ConcurrentHashMap。关注我的公众号“软件求生”,获取更多技术干货!
39 3
|
4天前
|
监控 Kubernetes Java
阿里面试:5000qps访问一个500ms的接口,如何设计线程池的核心线程数、最大线程数? 需要多少台机器?
本文由40岁老架构师尼恩撰写,针对一线互联网企业的高频面试题“如何确定系统的最佳线程数”进行系统化梳理。文章详细介绍了线程池设计的三个核心步骤:理论预估、压测验证和监控调整,并结合实际案例(5000qps、500ms响应时间、4核8G机器)给出具体参数设置建议。此外,还提供了《尼恩Java面试宝典PDF》等资源,帮助读者提升技术能力,顺利通过大厂面试。关注【技术自由圈】公众号,回复“领电子书”获取更多学习资料。
|
7天前
|
并行计算 算法 Java
Java中的Fork/Join框架详解
Fork/Join框架是Java并行计算的强大工具,尤其适用于需要将任务分解为子任务的场景。通过正确使用Fork/Join框架,可以显著提升应用程序的性能和响应速度。在实际应用中,应结合具体需求选择合适的任务拆分策略,以最大化并行计算的效率。
36 23
|
17天前
|
监控 Java
java异步判断线程池所有任务是否执行完
通过上述步骤,您可以在Java中实现异步判断线程池所有任务是否执行完毕。这种方法使用了 `CompletionService`来监控任务的完成情况,并通过一个独立线程异步检查所有任务的执行状态。这种设计不仅简洁高效,还能确保在大量任务处理时程序的稳定性和可维护性。希望本文能为您的开发工作提供实用的指导和帮助。
80 17
|
1月前
|
存储 监控 小程序
Java中的线程池优化实践####
本文深入探讨了Java中线程池的工作原理,分析了常见的线程池类型及其适用场景,并通过实际案例展示了如何根据应用需求进行线程池的优化配置。文章首先介绍了线程池的基本概念和核心参数,随后详细阐述了几种常见的线程池实现(如FixedThreadPool、CachedThreadPool、ScheduledThreadPool等)的特点及使用场景。接着,通过一个电商系统订单处理的实际案例,分析了线程池参数设置不当导致的性能问题,并提出了相应的优化策略。最终,总结了线程池优化的最佳实践,旨在帮助开发者更好地利用Java线程池提升应用性能和稳定性。 ####
|
1月前
|
监控 Java 开发者
深入理解Java中的线程池实现原理及其性能优化####
本文旨在揭示Java中线程池的核心工作机制,通过剖析其背后的设计思想与实现细节,为读者提供一份详尽的线程池性能优化指南。不同于传统的技术教程,本文将采用一种互动式探索的方式,带领大家从理论到实践,逐步揭开线程池高效管理线程资源的奥秘。无论你是Java并发编程的初学者,还是寻求性能调优技巧的资深开发者,都能在本文中找到有价值的内容。 ####
|
2月前
|
存储 缓存 安全
Java 集合框架优化:从基础到高级应用
《Java集合框架优化:从基础到高级应用》深入解析Java集合框架的核心原理与优化技巧,涵盖列表、集合、映射等常用数据结构,结合实际案例,指导开发者高效使用和优化Java集合。
58 4
|
SQL Java 数据库连接
Java面试题日积月累(SSM框架面试题22道)
Java面试题日积月累(SSM框架面试题22道)
105 0
|
6月前
|
设计模式 存储 安全
Java面试题:设计一个线程安全的单例类并解释其内存占用情况?使用Java多线程工具类实现一个高效的线程池,并解释其背后的原理。结合观察者模式与Java并发框架,设计一个可扩展的事件处理系统
Java面试题:设计一个线程安全的单例类并解释其内存占用情况?使用Java多线程工具类实现一个高效的线程池,并解释其背后的原理。结合观察者模式与Java并发框架,设计一个可扩展的事件处理系统
79 1
|
6月前
|
SQL Java 数据库连接
Java面试题:简述ORM框架(如Hibernate、MyBatis)的工作原理及其优缺点。
Java面试题:简述ORM框架(如Hibernate、MyBatis)的工作原理及其优缺点。
99 0