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日

相关文章

  • 详解Spring 中 Bean 对象的存储和取出

    下面是详解Spring中Bean对象的存储和取出的完整攻略: 目录 1. Spring中Bean对象的存储 1.1 BeanFactory 1.2 ApplicationContext 2. Spring中Bean对象的取出 2.1 通过名称获取Bean对象 2.2 通过类型获取Bean对象 3. 示例说明 3.1 示例1:通过名称获取Bean对象 3.2 …

    Java 2023年5月26日
    00
  • Java利用TreeUtils工具类实现列表转树

    下面是Java利用TreeUtils工具类实现列表转树的完整攻略。 1.准备工作 在进行列表转树操作前,需要先准备好列表数据。假设列表中每个元素都具有一个唯一标识符id和一个父元素标识符parentId,我们可以封装一个类来表示列表元素: public class TreeNode { private String id; private String pa…

    Java 2023年5月20日
    00
  • java生成图片验证码功能

    下面是详细讲解”Java生成图片验证码功能”的完整攻略: 1. 确定需求 首先,我们需要明确这个功能的需求,即在Java Web应用中生成一个随机的图片验证码,以用于用户填写和校验,防止机器人攻击或恶意提交。 2. 添加依赖 接下来,我们需要添加相关的依赖。Java中生成图片验证码需要用到jcaptcha这个开源工具包,我们可以在pom.xml中添加它的依赖…

    Java 2023年6月15日
    00
  • mybatis实现mapper代理模式的方式

    Mybatis是一款常用的ORM框架,提供了Mapper代理模式来替代直接使用JDBC操作数据库,可以大大简化代码量和提高开发效率。 下面是实现Mybatis的Mapper代理模式的步骤: 1. 定义Mapper接口 首先,我们需要定义一个Mapper接口,该接口下面定义了一些操作数据库的方法,这些方法的名称和参数与SQL语句的内容一一对应。例如: publ…

    Java 2023年5月19日
    00
  • 浅析12306售票算法(java版)

    浅析12306售票算法(Java版) 前言 12306售票算法是12306官方网站采用的一种购票算法,它采用的是先进先出的算法思想,即先处理最先提交的订单。在高并发情况下,这种算法能够确保订单售出的公平性,防止订单重复抢占,提高12306网站的稳定性。 算法流程 用户提交订单,服务器接收到请求后,将订单信息放入到队列中。 售票服务不断地从队列中取出订单。 售…

    Java 2023年5月20日
    00
  • 为什么继续选择DELPHI(即将逝去的Delphi前景在何方)

    为什么继续选择DELPHI(即将逝去的Delphi前景在何方) 背景 Delphi是一种基于Object Pascal编程语言的集成开发环境,由Borland公司在1995年发布。自发布以来,Delphi为数不少的开发者提供了稳定快捷、功能丰富的编程环境。然而,随着新的技术不断涌现,Delphi市场份额逐渐萎缩,导致一些人对其前景存在疑虑。但是,选择Delp…

    Java 2023年5月19日
    00
  • SpringBoot 钩子接口的实现代码

    在SpringBoot中,我们可以通过实现钩子接口(Hook Interface)来在启动应用程序或者关闭应用程序时执行一些特定的逻辑行为。例如我们可以在应用启动时预加载某些资源,或者在应用关闭时清理一些资源等。本文将为大家介绍如何实现SpringBoot钩子接口,包含以下步骤: 新建Hook Interface 首先,我们需要新建一个Hook Interf…

    Java 2023年5月31日
    00
  • Java线程重复执行以及操作共享变量的代码示例

    Java线程是一种轻量级进程,可以同时执行多个线程,实现并发操作。有时候我们需要让线程重复执行某个任务,并且需要注意操作共享变量的线程安全问题。下面就是以代码示例的形式,详细讲解“Java线程重复执行以及操作共享变量”的完整攻略。 线程重复执行 线程重复执行的方式有多种,其中最常见的方式是使用循环语句,如while循环、for循环等。下面以while循环和延…

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