线程池与并发工具:优化多线程执行!

开篇语

哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云/阿里云/华为云/51CTO;欢迎大家常来逛逛

  今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一个人虽可以走的更快,但一群人可以走的更远。

  我是一名后端开发爱好者,工作日常接触到最多的就是Java语言啦,所以我都尽量抽业余时间把自己所学到所会的,通过文章的形式进行输出,希望以这种方式帮助到更多的初学者或者想入门的小伙伴们,同时也能对自己的技术进行沉淀,加以复盘,查缺补漏。

小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦。三连即是对作者我写作道路上最好的鼓励与支持!

前序

在Java中,创建和管理线程是一个资源密集型的任务,尤其是在高并发的应用中。每次创建新线程都会消耗大量的时间和系统资源。为了避免这种性能瓶颈,Java提供了线程池和相关的并发工具。线程池通过复用现有的线程来执行多个任务,从而显著提高程序的执行效率,并减少系统资源的浪费。

本文将介绍Executor框架线程池的使用,以及CallableFuture接口的使用方式。


前言

线程池是多线程编程中不可或缺的工具,它能够有效地管理线程的生命周期,避免频繁创建和销毁线程的开销,提升并发程序的性能。在Java中,Executor框架提供了非常灵活且强大的线程池管理功能。通过使用线程池,我们可以轻松地控制任务的执行,管理线程,处理任务的返回值。


第一部分:Executor框架与线程池

1.1 什么是Executor框架?

Executor框架是Java 5引入的一种用于处理并发任务的高级框架,它通过ExecutorExecutorServiceScheduledExecutorService接口来提供线程池管理功能。与传统的线程管理方法相比,Executor框架简化了线程的创建、调度和管理过程。

Executor框架主要包括以下几种组件:

  • Executor接口:是所有线程池的父接口,提供了一个执行任务的标准方法execute(Runnable command)
  • ExecutorService接口:继承自Executor,添加了用于管理任务生命周期的方法,如submit()shutdown()等。
  • ScheduledExecutorService接口:继承自ExecutorService,提供了定时和周期性任务的调度能力。

1.2 创建线程池

Java提供了Executors类来创建不同类型的线程池。常见的线程池包括:

  • FixedThreadPool:一个固定大小的线程池,适用于任务数量固定且大小合适的场景。
  • CachedThreadPool:一个可缓存的线程池,根据需要创建新线程,适用于执行许多短期异步任务。
  • SingleThreadExecutor:一个单线程的线程池,适用于顺序执行任务的场景。
示例:创建一个固定大小的线程池
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExecutorExample {
    public static void main(String[] args) {
        // 创建一个固定大小的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(3);

        // 提交多个任务
        for (int i = 0; i < 5; i++) {
            executorService.submit(() -> {
                System.out.println(Thread.currentThread().getName() + " is executing a task.");
            });
        }

        // 关闭线程池
        executorService.shutdown();
    }
}

解释:

  • Executors.newFixedThreadPool(3)创建了一个大小为3的线程池。
  • submit()方法将任务提交给线程池进行执行。线程池会根据可用线程执行任务。
  • 最后调用shutdown()方法关闭线程池,等待所有任务执行完毕。

1.3 线程池的优点

  • 提高性能:线程池通过复用线程来执行多个任务,避免了频繁创建和销毁线程的开销。
  • 管理线程:线程池可以动态调整线程数量,处理不同类型的任务。
  • 避免资源浪费:线程池合理地管理线程,避免了创建过多线程而导致的系统资源浪费。

第二部分:Callable与Future接口

2.1 Callable接口与Runnable接口

RunnableCallable都是用于定义任务的接口,但它们有几个不同之处:

  • Runnable:没有返回值,run()方法不抛出异常。
  • Callable:有返回值,call()方法可以返回结果,并且可以抛出异常。

Callable接口是ExecutorService框架中用来执行任务并获取返回值的标准接口。相比RunnableCallable更加灵活,适合需要返回结果或者处理异常的任务。

示例:使用Callable接口
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class CallableExample {
    public static void main(String[] args) throws Exception {
        // 创建一个固定大小的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(2);

        // 创建一个Callable任务
        Callable<Integer> task = () -> {
            System.out.println(Thread.currentThread().getName() + " is executing a task.");
            return 42;  // 返回任务的结果
        };

        // 提交任务并获取Future对象
        Future<Integer> future = executorService.submit(task);

        // 获取任务的结果
        Integer result = future.get();  // 阻塞直到任务完成
        System.out.println("Task result: " + result);

        // 关闭线程池
        executorService.shutdown();
    }
}

解释:

  • Callable<Integer> task是一个任务,它返回一个Integer类型的结果。
  • submit()方法提交任务并返回一个Future对象,通过Future.get()方法可以获取任务的执行结果。如果任务还没有完成,get()方法会阻塞直到任务完成。
  • shutdown()方法关闭线程池。

2.2 Future接口

Future接口用于表示异步计算的结果。通过Future对象,我们可以检查任务是否完成、取消任务,或者获取任务的结果。Future接口常用于异步任务的执行。

常用的方法:

  • get():阻塞并等待任务完成,返回任务的结果。
  • isDone():检查任务是否完成。
  • cancel(boolean mayInterruptIfRunning):取消任务的执行。
示例:使用Future检查任务状态
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class FutureExample {
    public static void main(String[] args) throws Exception {
        ExecutorService executorService = Executors.newFixedThreadPool(2);

        // 创建一个Callable任务
        Callable<String> task = () -> {
            Thread.sleep(2000);  // 模拟长时间运行的任务
            return "Task completed!";
        };

        Future<String> future = executorService.submit(task);

        // 检查任务是否完成
        while (!future.isDone()) {
            System.out.println("Task is still running...");
            Thread.sleep(500);
        }

        // 获取任务的结果
        System.out.println(future.get());  // 输出:Task completed!

        executorService.shutdown();
    }
}

解释:

  • future.isDone()方法用于检查任务是否完成。如果任务还在执行,isDone()返回false,否则返回true
  • future.get()方法会阻塞直到任务完成并返回任务的结果。

第三部分:线程池的调优与管理

3.1 线程池的调优

线程池的性能调优涉及多个方面,包括线程池的大小、任务队列的配置以及拒绝策略等。合理配置线程池能够提高并发性能,避免线程池资源浪费或线程过多导致的性能问题。

常见的调优参数:

  • 核心池大小corePoolSize):线程池的核心线程数量。如果线程池中没有空闲线程,且提交的任务数量超过核心线程数,线程池将创建新的线程(最多到最大线程数)。
  • 最大池大小maximumPoolSize):线程池中允许的最大线程数。
  • 线程空闲时间keepAliveTime):如果线程池中的线程数超过核心线程数,空闲线程在多长时间后会被销毁。
  • 任务队列BlockingQueue):线程池使用队列来存放等待执行的任务。常见的队列类型有ArrayBlockingQueueLinkedBlockingQueue等。
示例:创建自定义线程池
import java.util.concurrent.*;

public class CustomThreadPoolExample {
    public static void main(String[] args) {
        // 创建一个带有自定义配置的线程池
        ExecutorService executorService = new ThreadPoolExecutor(
            2,  // corePoolSize
            4,  // maximumPoolSize
            60L, TimeUnit.SECONDS,  // keepAliveTime
            new ArrayBlockingQueue<>(10),  // workQueue
            new ThreadPoolExecutor.CallerRunsPolicy()  // Rejection policy
        );

        for (int i = 0; i < 10; i++) {
            executorService.submit(() -> {
                System.out.println(Thread.currentThread().getName() + " is executing task.");
            });
        }

        executorService.shutdown();
    }
}

解释:

  • corePoolSize设置为2,maximumPoolSize设置为4,线程池的大小将在这两个范围之间动态调整。
  • keepAliveTime设置为60秒,空闲线程在60秒后被销毁。
  • 使用ArrayBlockingQueue作为任务队列,队列容量为10。
  • CallerRunsPolicy是一个拒绝策略,当任务数量超出最大线程池容量时,当前调用线程会执行任务,而不是将任务丢弃或抛出异常。

总结

Java的Executor框架和线程池提供了一个高效的方式来管理多线程任务。通过使用ExecutorService创建线程池,我们可以有效地管理线程的生命周期,提高系统的并发能力。CallableFuture接口为我们提供了一个强大的异步编程机制,允许我们在执行任务时获取结果并检查任务状态。

合理调优线程池的配置,可以进一步提高程序的性能和稳定性。通过掌握这些并发工具,我们可以在高并发场景下写出更加高效、稳定的代码。

… …

文末

好啦,以上就是我这期的全部内容,如果有任何疑问,欢迎下方留言哦,咱们下期见。

… …

学习不分先后,知识不分多少;事无巨细,当以虚心求教;三人行,必有我师焉!!!

wished for you successed !!!


⭐️若喜欢我,就请关注我叭。

⭐️若对您有用,就请点赞叭。
⭐️若有疑问,就请评论留言告诉我叭。


版权声明:本文由作者原创,转载请注明出处,谢谢支持!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值