Java线程池的几种实现方法和区别介绍实例详解

Java线程池的几种实现方法和区别介绍

什么是线程池

在线程池中,线程的创建和销毁都由线程池管理器来处理,线程池中包括一组线程,线程池会根据配置的参数来动态调整线程池中线程的数量。线程池中的线程可以被多个任务共享,使线程的创建和销毁开销及竞争锁等问题得以优化。

为什么要使用线程池

线程池的主要目的是为了控制并发执行的线程数,有以下几个优点:

  • 降低线程的创建和销毁的开销。
  • 重复利用已经创建的线程,避免创建新的线程所带来的开销。
  • 避免大量线程抢占系统资源导致系统负载过大而崩溃的风险。
  • 更好地管理线程,提供更加灵活,强大的线程管理能力。

线程池的实现方法

在Java中,线程池是由java.util.concurrent包提供的,其中提供了多种类型的线程池,常用的有以下几种:

  • newFixedThreadPool
  • newCachedThreadPool
  • newScheduledThreadPool
  • newSingleThreadExecutor
  • ThreadPoolExecutor

newFixedThreadPool

newFixedThreadPool(int nThreads)方法创建一个有固定大小的线程池,每次提交一个任务就创建一个线程,直到线程数量达到线程池的最大容量。线程池的大小一旦达到最大值,就会保持不变,如果有多余的任务需要执行,就必须等待线程池有空闲的线程才能执行。

示例代码:

ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);

for (int i = 0; i < 10; i++) {
    fixedThreadPool.execute(new Task(i));
}

该示例代码会创建一个大小为5的线程池,接着往线程池中提交了10个任务。由于线程池的大小为5,因此最多同时执行5个任务,剩下的任务会等待有空闲的线程再去执行。

newCachedThreadPool

newCachedThreadPool()方法创建一个可缓存的线程池,如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲的线程,当任务数增加时,会自动添加新的线程来处理任务。

示例代码:

ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

for (int i = 0; i < 10; i++) {
    cachedThreadPool.execute(new Task(i));
}

该示例代码会创建一个可缓存的线程池,接着往线程池中提交了10个任务。由于线程池的大小没有限制,因此可以同时执行10个任务。

newScheduledThreadPool

newScheduledThreadPool(int corePoolSize)方法创建一个固定大小的线程池,可以定时或延时执行任务。该方法返回一个ScheduledExecutorService对象,该对象可以在指定延时后执行任务或按固定延时周期执行任务。

示例代码:

ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);

scheduledThreadPool.schedule(new Task(1), 2, TimeUnit.SECONDS);
scheduledThreadPool.scheduleAtFixedRate(new Task(2), 2, 1, TimeUnit.SECONDS);

该示例代码会创建一个大小为5的定时线程池,接着往线程池中提交了两个任务,其中第一个任务会在2秒后执行一次,第二个任务则会在2秒后开始执行,每隔1秒执行一次。

newSingleThreadExecutor

newSingleThreadExecutor()方法创建一个单线程的线程池,所有任务都在同一个线程中执行,保证了所有任务的顺序执行,也避免了线程间的竞争问题。

示例代码:

ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();

for (int i = 0; i < 10; i++) {
    singleThreadExecutor.execute(new Task(i));
}

该示例代码会创建一个单线程的线程池,接着往线程池中提交了10个任务。由于是单线程的线程池,因此所有任务都会按照提交的顺序依次执行。

ThreadPoolExecutor

ThreadPoolExecutor是通过Executors工厂类提供的方法之外,直接创建线程池的实现类,这个类的构造方法比较复杂,需要传入7个参数,分别是:

public ThreadPoolExecutor(int corePoolSize, // 核心线程数
                              int maximumPoolSize, // 最大线程数
                              long keepAliveTime, // 线程最大空闲时间
                              TimeUnit unit, // 时间单位
                              BlockingQueue<Runnable> workQueue, // 等待队列
                              ThreadFactory threadFactory, // 线程工厂
                              RejectedExecutionHandler handler // 拒绝策略
                             )

示例代码:

BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(10);
ExecutorService threadPoolExecutor = new ThreadPoolExecutor(
        2, // 核心线程数
        4, // 最大线程数
        1, // 线程最大空闲时间
        TimeUnit.MINUTES, // 时间单位
        queue, // 等待队列
        Executors.defaultThreadFactory(), // 线程工厂
        new ThreadPoolExecutor.AbortPolicy()); // 拒绝策略

for (int i = 0; i < 10; i++) {
    threadPoolExecutor.execute(new Task(i));
}

该示例代码会手动创建一个线程池,该线程池的核心线程数为2,最大线程数为4,空闲线程最长等待时间为1分钟,等待队列容量为10,拒绝策略为丢弃任务并抛出异常。接着往线程池中提交了10个任务,在这个示例中,因为线程池容量不够,多余的任务会被等待队列中的消息存储,直到有空闲线程时,线程池才会将消息从等待队列中取走,进行任务处理。

总结

以上就是Java线程池的几种实现方法及其区别介绍。根据不同需求,选择合适的线程池会更好地提升系统性能、压力测试和控制流量。

参考文献

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java线程池的几种实现方法和区别介绍实例详解 - Python技术站

(0)
上一篇 2023年5月18日
下一篇 2023年5月18日

相关文章

  • Springboot 全局时间格式化操作

    下面是关于Spring Boot全局时间格式化操作的完整攻略。 背景 Spring Boot是一个使用很方便的轻量级框架,它内置了很多常用的扩展功能。在实际应用中,我们经常需要对时间类型数据进行格式化处理,以满足业务需求。此时,全局时间格式化就成了必不可少的一个功能。 解决方案 方案一:在全局配置文件中配置时间格式 可以在application.proper…

    Java 2023年5月20日
    00
  • jdk线程池的实现

    关于“jdk线程池的实现”的攻略,我们可以分为以下几个部分来讲解: 1. 线程池原理和作用 线程池是一种常用的异步并发编程技术。其作用是在程序运行时提前创建一定数量的线程,这些线程被用来执行一些任务,一旦任务执行完毕,线程不会被销毁,而是等待被下一个任务调用。这样可以减少线程的创建和销毁,提高程序的性能和稳定性。 2. jdk线程池的实现 在JDK中,提供了…

    Java 2023年5月19日
    00
  • Java启动Tomcat的实现步骤

    Java启动Tomcat的实现步骤如下: 1. 确认Tomcat安装目录 首先需要确认Tomcat安装目录,以便后续操作。假设Tomcat的安装目录为 /usr/local/tomcat8。 2. 设置JAVA_HOME环境变量 在启动Tomcat之前,需要设置JAVA_HOME环境变量,确保Java环境可用。在Linux系统中,可以通过以下命令设置: ex…

    Java 2023年5月19日
    00
  • Java中的静态内部类是什么?

    Java中的静态内部类是一种内部类,它具有访问外部类的静态成员变量和方法的能力。它与外部类的静态成员是相似的,可以通过类名直接访问。 定义静态内部类 静态内部类的定义方式与成员内部类的定义方式类似,只是需要在内部类名称前面加上static关键字。以下是一个示例: public class OuterClass { private static String …

    Java 2023年4月27日
    00
  • gateway、webflux、reactor-netty请求日志输出方式

    为了让大家更好地了解 “gateway、webflux、reactor-netty请求日志输出方式”,我将分别讲解这三个主题,并提供相应的示例代码,在此之前,请确保已经安装好了Java环境,并了解基本的Spring Boot框架。 Gateway请求日志输出方式 Gateway是Spring Cloud的组件之一,可以将多个微服务组合起来作为一个整体对外提供…

    Java 2023年5月20日
    00
  • java追加写入txt文件的方法总结

    下面是详细讲解“Java追加写入txt文件的方法总结”的完整攻略。 1. 前言 在Java开发中,我们经常需要将程序的结果或相关数据写入到本地文件中。而在文件操作中,「追加写入」是一个非常重要的操作。相比于「覆盖写入」,追加写入可以在原有文件基础上新增内容,不会破坏已有数据。 2. 追加写入的方法 2.1. 使用FileWriter类 FileWriter类…

    Java 2023年5月19日
    00
  • Java 在游戏中探索数组二维数组

    Java 在游戏中探索数组二维数组 什么是数组和二维数组 在 Java 编程中,数组就是一个固定大小的容器,可以用来存储一组相同类型的数据。如果我们需要将一组数据存储起来,而且这组数据的类型相同且数量确定,那么数组就是最好的选择。 二维数组是由多个一维数组组成的。它可以看做是一个表格,每个一维数组就相当于表格的一行,而每个元素就相当于表格中的一个单元格。二维…

    Java 2023年5月26日
    00
  • Spring-data-redis操作redis知识总结

    Spring-data-redis操作redis知识总结 Spring-data-redis是Spring Framework提供的针对Redis的功能性扩展,支持面向对象、具有一致抽象的Redis数据访问技术。本文将重点介绍Spring-data-redis操作Redis的相关知识总结。 Spring-data-redis操作Redis的基本步骤 添加Re…

    Java 2023年5月20日
    00
合作推广
合作推广
分享本页
返回顶部