【Java并发编程 十二】JUC并发包下线程池(下)

简介: 【Java并发编程 十二】JUC并发包下线程池(下)

执行示例

描述一下线程池工作的原理,同时对上面的参数有一个更深的了解。其工作原理流程图如下图片来源

可以简单的总结如下:

  1. 如果当前线程池中的线程数目小于corePoolSize,则每来一个任务,就会创建一个线程去执行这个任务;
  2. 如果当前线程池中的线程数目>=corePoolSize,则每来一个任务,会尝试将其添加到任务缓存队列当中,
    - 若当前任务数<workQueue容量,添加成功,则该任务会等待空闲线程将其取出去执行
    - 若当前任务数>workQueue容量,添加失败,则会尝试创建新的线程去执行这个任务
  3. 如果当前线程池中的线程数目没有达到maximumPoolSize,则会创建新线程执行任务,并且根据keepAlive设置的闲置时间会自动销毁
  4. 如果当前线程池中的线程数目和任务队列都满了,则会采取任务拒绝策略进行处理;

需要注意,如果允许为核心池中的线程设置存活时间,那么核心池中的线程空闲时间超过keepAliveTime,线程也会被终止。

预置线程池

Executors中为我们预置了几种线程池,而让我们不必考虑上述线程池的一些参数,可以理解为一些最佳实践,这里列举一下以及简单介绍下它们的作用,定长线程池(FixedThreadPool), 定时线程池(ScheduledThreadPool ),可缓存线程池(CachedThreadPool)单线程化线程池(SingleThreadExecutor)四种,接下来分别从源码和使用的角度介绍下。

定长线程池

创建方法有两个重载方法,定长线程池的特点是,只有核心线程,线程数量固定,执行完立即回收,任务队列为链表结构的有界队列

public static ExecutorService newFixedThreadPool(int nThreads) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>());
    }
       public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>(),
                                      threadFactory);
    }

应用场景主要是控制线程最大并发数,使用示例如下:

package com.company;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadTest {
    public static void main(String[] args)   {
        //1. 创建定长线程池对象 & 设置线程池线程数量固定为2
        ExecutorService threadPool = Executors.newFixedThreadPool(2);
        // 2. 创建好Runnable类线程对象 & 需执行的任务
        Runnable task1 = () -> System.out.println(Thread.currentThread().getName() + " 执行任务");
        Runnable task2 = () -> System.out.println(Thread.currentThread().getName() + " TML发出指令");
        // 3. 向线程池提交任务
        threadPool.execute(task1);
        threadPool.execute(task2);
        // 4. 关闭线程池
        threadPool.shutdown();
    }
}

返回结果如下:

pool-1-thread-1 执行任务
pool-1-thread-2 TML发出指令

定时线程池(ScheduledThreadPool )

创建方法的源码如下,特点是核心线程数量固定,非核心线程数量无限,执行完闲置10ms后回收,任务队列为延时阻塞队列

private static final long DEFAULT_KEEPALIVE_MILLIS = 10L;
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}
public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE,
          DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
          new DelayedWorkQueue());
}
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory) {
    return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
}
public ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory) {
    super(corePoolSize, Integer.MAX_VALUE,
          DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
          new DelayedWorkQueue(), threadFactory);
}

应用场景主要是执行定时或周期性的任务,使用示例如下:

package com.company;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ThreadTest {
    public static void main(String[] args) throws InterruptedException {
        //1. 创建定长线程池对象 & 设置线程池线程数量固定为2
        ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(2);
        // 2. 创建好Runnable类线程对象 & 需执行的任务
        Runnable task1 = () -> System.out.println(Thread.currentThread().getName() + " 执行任务");
        Runnable task2 = () -> System.out.println(Thread.currentThread().getName() + " TML发出指令");
        // 3. 向线程池提交任务
        threadPool.schedule(task1, 1, TimeUnit.SECONDS); // 延迟1s后执行任务
        threadPool.scheduleAtFixedRate(task2,10,1000,TimeUnit.MILLISECONDS);// 延迟10ms后、每隔1000ms执行任务
        Thread.sleep(10000);
        // 4. 关闭线程池
        threadPool.shutdown();
    }
}

打印结果如下:

pool-1-thread-1 TML发出指令
pool-1-thread-2 执行任务
pool-1-thread-1 TML发出指令
pool-1-thread-1 TML发出指令
pool-1-thread-1 TML发出指令
pool-1-thread-1 TML发出指令
pool-1-thread-1 TML发出指令
pool-1-thread-1 TML发出指令
pool-1-thread-1 TML发出指令
pool-1-thread-1 TML发出指令
pool-1-thread-1 TML发出指令

可缓存线程池(CachedThreadPool)

创建方法的源码如下,特点是无核心线程,非核心线程数量无限,执行完闲置60s后回收,任务队列为不存储元素的阻塞队列

public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>(),
                                  threadFactory);
}

应用场景主要为执行大量、耗时少的任务,示例如下:

package com.company;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadTest {
    public static void main(String[] args) throws InterruptedException {
        //1. 创建定长线程池对象 & 设置线程池线程数量固定为2
        ExecutorService threadPool = Executors.newCachedThreadPool();
        // 2. 创建好Runnable类线程对象 & 需执行的任务
        Runnable task1 = () -> System.out.println(Thread.currentThread().getName() + " 执行任务");
        Runnable task2 = () -> System.out.println(Thread.currentThread().getName() + " TML发出指令");
        // 3. 向线程池提交任务
        threadPool.execute(task1); 
        threadPool.execute(task2);
        Thread.sleep(10000);
        // 4. 关闭线程池
        threadPool.shutdown();
    }
}

返回结果与定长线程池类似。

单线程化线程池(SingleThreadExecutor)

创建方法的源码如下,主要特点为只有1个核心线程,无非核心线程,执行完立即回收,任务队列为链表结构的有界队列

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>(),
                                threadFactory));
}

应用场景为不适合并发但可能引起IO阻塞性及影响UI线程响应的操作,如数据库操作、文件操作等,执行示例如下:

package com.company;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ThreadTest {
    public static void main(String[] args) throws InterruptedException {
        //1. 创建定长线程池对象 & 设置线程池线程数量固定为2
        ExecutorService threadPool = Executors.newSingleThreadExecutor();
        // 2. 创建好Runnable类线程对象 & 需执行的任务
        Runnable task1 = () -> System.out.println(Thread.currentThread().getName() + " 执行任务");
        Runnable task2 = () -> System.out.println(Thread.currentThread().getName() + " TML发出指令");
        // 3. 向线程池提交任务
        threadPool.execute(task1); 
        threadPool.execute(task2);
        Thread.sleep(10000);
        // 4. 关闭线程池
        threadPool.shutdown();
    }
}

通过返回结果可以看出,只有一个线程发挥作用:

pool-1-thread-1 执行任务
pool-1-thread-1 TML发出指令

以上的这几种都是预置线程,其实更推荐大家使用自定义的方式依据业务场景传入合适的参数构造自己业务专属的线程池。

相关文章
|
1月前
|
安全 Java 测试技术
Java并行流陷阱:为什么指定线程池可能是个坏主意
本文探讨了Java并行流的使用陷阱,尤其是指定线程池的问题。文章分析了并行流的设计思想,指出了指定线程池的弊端,并提供了使用CompletableFuture等替代方案。同时,介绍了Parallel Collector库在处理阻塞任务时的优势和特点。
|
24天前
|
存储 监控 小程序
Java中的线程池优化实践####
本文深入探讨了Java中线程池的工作原理,分析了常见的线程池类型及其适用场景,并通过实际案例展示了如何根据应用需求进行线程池的优化配置。文章首先介绍了线程池的基本概念和核心参数,随后详细阐述了几种常见的线程池实现(如FixedThreadPool、CachedThreadPool、ScheduledThreadPool等)的特点及使用场景。接着,通过一个电商系统订单处理的实际案例,分析了线程池参数设置不当导致的性能问题,并提出了相应的优化策略。最终,总结了线程池优化的最佳实践,旨在帮助开发者更好地利用Java线程池提升应用性能和稳定性。 ####
|
21天前
|
监控 Java 开发者
深入理解Java中的线程池实现原理及其性能优化####
本文旨在揭示Java中线程池的核心工作机制,通过剖析其背后的设计思想与实现细节,为读者提供一份详尽的线程池性能优化指南。不同于传统的技术教程,本文将采用一种互动式探索的方式,带领大家从理论到实践,逐步揭开线程池高效管理线程资源的奥秘。无论你是Java并发编程的初学者,还是寻求性能调优技巧的资深开发者,都能在本文中找到有价值的内容。 ####
|
1月前
|
安全 Java
线程安全的艺术:确保并发程序的正确性
在多线程环境中,确保线程安全是编程中的一个核心挑战。线程安全问题可能导致数据不一致、程序崩溃甚至安全漏洞。本文将分享如何确保线程安全,探讨不同的技术策略和最佳实践。
41 6
|
28天前
|
存储 缓存 监控
Java中的线程池深度解析####
本文深入探讨了Java并发编程中的核心组件——线程池,从其基本概念、工作原理、核心参数解析到应用场景与最佳实践,全方位剖析了线程池在提升应用性能、资源管理和任务调度方面的重要作用。通过实例演示和性能对比,揭示合理配置线程池对于构建高效Java应用的关键意义。 ####
|
1月前
|
安全 Java 开发者
Java 多线程并发控制:深入理解与实战应用
《Java多线程并发控制:深入理解与实战应用》一书详细解析了Java多线程编程的核心概念、并发控制技术及其实战技巧,适合Java开发者深入学习和实践参考。
58 6
|
1月前
|
存储 安全 Java
Java多线程编程中的并发容器:深入解析与实战应用####
在本文中,我们将探讨Java多线程编程中的一个核心话题——并发容器。不同于传统单一线程环境下的数据结构,并发容器专为多线程场景设计,确保数据访问的线程安全性和高效性。我们将从基础概念出发,逐步深入到`java.util.concurrent`包下的核心并发容器实现,如`ConcurrentHashMap`、`CopyOnWriteArrayList`以及`BlockingQueue`等,通过实例代码演示其使用方法,并分析它们背后的设计原理与适用场景。无论你是Java并发编程的初学者还是希望深化理解的开发者,本文都将为你提供有价值的见解与实践指导。 --- ####
|
1月前
|
存储 设计模式 分布式计算
Java中的多线程编程:并发与并行的深度解析####
在当今软件开发领域,多线程编程已成为提升应用性能、响应速度及资源利用率的关键手段之一。本文将深入探讨Java平台上的多线程机制,从基础概念到高级应用,全面解析并发与并行编程的核心理念、实现方式及其在实际项目中的应用策略。不同于常规摘要的简洁概述,本文旨在通过详尽的技术剖析,为读者构建一个系统化的多线程知识框架,辅以生动实例,让抽象概念具体化,复杂问题简单化。 ####
|
1月前
|
监控 安全 Java
Java中的多线程编程:从入门到实践####
本文将深入浅出地探讨Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的摘要形式,本文将以一个简短的代码示例作为开篇,直接展示多线程的魅力,随后再详细解析其背后的原理与实现方式,旨在帮助读者快速理解并掌握Java多线程编程的基本技能。 ```java // 简单的多线程示例:创建两个线程,分别打印不同的消息 public class SimpleMultithreading { public static void main(String[] args) { Thread thread1 = new Thread(() -> System.out.prin
|
1月前
|
安全 Java 调度
Java中的多线程编程入门
【10月更文挑战第29天】在Java的世界中,多线程就像是一场精心编排的交响乐。每个线程都是乐团中的一个乐手,他们各自演奏着自己的部分,却又和谐地共同完成整场演出。本文将带你走进Java多线程的世界,让你从零基础到能够编写基本的多线程程序。
37 1