0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Java中的线程池包括哪些

科技绿洲 来源:Java技术指北 作者:Java技术指北 2023-10-11 15:33 次阅读

线程池是用来统一管理线程的,在 Java 中创建和销毁线程都是一件消耗资源的事情,线程池可以重复使用线程,不再频繁的创建、销毁线程。

初识

Java 中的线程池是由 juc 即 java.util.concurrent 包来实现的,最主要的就是 ThreadPoolExecutor 类。

图片

  1. Executor: 代表线程池的接口,有一个 execute() 方法,给一个 Runnable 类型对象就可以分配一个线程执行。
  2. ExecutorService:是 Executor 的子接口,提供了线程池的一些生命周期方法。代表了一个线程池管理器。
  3. ThreadPoolExecutor:一个线程池的实现类,可以通过调用 Executors 静态工厂方法来创建线程池并返回一个 ExecutorService 对象。

ThredadPoolExcutor

看一下最常用的 ThredadPoolExcutor ,下图是 ThreadPoolExecutor 的构造函数

图片

从源码中可以看出每个前三个构造函数都调用了最后一个构造函数。

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue< Runnable > workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
    //省略代码
    }

仔细分析一下构造参数

  1. corePoolSize:线程池里的核心线程数量,当正在运行的线程数量小于核心线程数量,就创建一个核心线程。
  2. maximumPoolSize:线程池最多能放多少个线程。
  3. keepAliveTime:线程的闲置时间,当线程池里面的线程数量大于 corePoolSize 的时候,多出来的线程在等待的时间之后会被释放掉
  4. unit:keepAliveTime 的单位
  5. workQueue:一个阻塞队列。
  6. threadFactory:通过这个工厂模式创建线程。
  7. handler:处理线程队列满了报错的。

结合线程池的参数简单的画出线程池的工作模型。

图片

当线程池中的核心线程数量 corePoolSize 满了,就会将任务先加入到任务队列 workQueue 中。

执行过程

线程池的执行过程如下图:

  1. 首先判断核心线程 corePoolSize 是不是满了,如果没有满,就执行任务,否则就进入下一步。
  2. 线程池判断任务队列 workQueue 是否了,如果没有满,则将新提交的任务放入在这个任务队列里。如果任务队列满了,则进入一步。
  3. 判断线程池里的线程达到了最大线程数 maximumPoolSize,如果没有,则创建一个新的线程来执行任务。如果已经满了,则交给拒绝策略来处理这个任务。

图片

常用的线程池

线程池的创建需要有 7 个参数,还是比较复杂的,JVM 为我们提供了 Executors 类中多个静态工厂,生成一些常用的线程池。

SingleThreadExecutor

单线程的线程池,里面就一个核心线程数。

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

ThreadPoolExecutor 参数只有一个核心线程数和一个最大线程数,这个很少用到。它保证了所有线程的执行顺序都是按照提交到线程池的顺序执行。

public class TodoDemo implements Runnable {


    public static void main(String[] args) {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        for(int i = 0; i < 10; i++) {
            executorService.execute(new TodoDemo());
        }
        executorService.shutdown();
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " Running");
    }
}

只有一个线程在跑。

图片

FixedThreadExecutor

固定数量的线程池

return new ThreadPoolExecutor(nThreads, nThreads,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue< Runnable >());
}

这个线程池的特点就是线程的数量是固定的,超过这个数量的任务就得在 LinkedBlockingQueue 中排队等候。

public class TodoDemo implements Runnable {
    
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        for(int i = 0; i < 10; i++) {
            executorService.execute(new TodoDemo());
        }
        executorService.shutdown();
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " Running");
    }
}

可以看到就算提交 100 个任务也只有 3 个线程。

图片

CachedThreadExecutor

自动回收空闲的线程

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

可以看到核心线程数量为 0, 表示不会永久保留任何的线程,最大线程的数量是 Integer.MAX_VALUE,可以无限制的创建线程,但是当有大量线程处于空闲状态的时候,超过 60s 就会被销毁。

public class TodoDemo implements Runnable {

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        for(int i = 0; i < 20; i++) {
            executorService.execute(new TodoDemo());
        }
        executorService.shutdown();
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " Running");
    }
}

虽然这个线程池可以想建多少个线程就建多少个线程,但是还是会重用已经完成任务的线程。

图片

一般最常用的是FixedThreadExecutor和CachedThreadExecutor。

线程池的回收策略

在线程池中任务队列已经满了,并且线程的数量已经到了最大的数量,这个时候再加任务线程池就不再接受了。

在 ThreadPoolExecutor 里有 4 种拒绝策略,都实现了 RejectedExecutionHandler:

  1. AbortPolicy 表示抛出一个异常。
  2. DiscardPolicy 拒绝任务但是不提示。
  3. DiscardOldestPolicy 丢弃掉老的任务,执行新的任务。
  4. CallerRunsPolicy 直接调用线程处理。

总结

线程池的作用是提高系统的性能和线程的利用率,不再需要频繁的创建和销毁线程。如果使用最简单的方式创建线程,在用户量巨大的情况下,消耗的性能是非常恐怖的,所以才有了线程池。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 接口
    +关注

    关注

    33

    文章

    8583

    浏览量

    151075
  • JAVA
    +关注

    关注

    19

    文章

    2967

    浏览量

    104729
  • 管理器
    +关注

    关注

    0

    文章

    246

    浏览量

    18505
  • 函数
    +关注

    关注

    3

    文章

    4329

    浏览量

    62585
  • 线程池
    +关注

    关注

    0

    文章

    57

    浏览量

    6846
收藏 人收藏

    评论

    相关推荐

    Java线程的用法

    本文将介绍一下Java线程的用法。 基础介绍 什么是多线程 指的是在一个进程同时运行多个线程,每个线
    的头像 发表于 09-30 17:07 948次阅读

    动态线程思想学习及实践

    ://www.javadoop.com/post/java-thread-pool 引言 在后台项目开发过程,我们常常借助线程来实现多线程
    的头像 发表于 06-13 15:43 1184次阅读
    动态<b class='flag-5'>线程</b><b class='flag-5'>池</b>思想学习及实践

    线程是如何实现的

    线程的概念是什么?线程是如何实现的?
    发表于 02-28 06:20

    java自带的线程方法

    二、原理分析 从上面使用线程的例子来看,最主要就是两步,构造ThreadPoolExecutor对象,然后每来一个任务,就调用ThreadPoolExecutor对象的execute方法。 1
    发表于 09-27 11:06 0次下载

    如何正确关闭线程

    /huajiexiewenfeng/java-concurrent 本章模块:threadpool 1.线程示例 public class ShutDownThreadPoolDemo { private
    的头像 发表于 09-29 14:41 9914次阅读

    线程线程

    线程通常用于服务器应用程序。 每个传入请求都将分配给线程池中的一个线程,因此可以异步处理请求,而不会占用主线程,也不会延迟后续请求的处理
    的头像 发表于 02-28 09:53 789次阅读
    多<b class='flag-5'>线程</b>之<b class='flag-5'>线程</b><b class='flag-5'>池</b>

    Java线程核心原理

    看过Java线程源码的小伙伴都知道,在Java线程池中最核心的类就是ThreadPoolExecutor,
    的头像 发表于 04-21 10:24 855次阅读

    Spring 的线程应用

    我们在日常开发,经常跟多线程打交道,Spring 为我们提供了一个线程方便我们开发,它就是 ThreadPoolTaskExecutor ,接下来我们就来聊聊 Spring 的
    的头像 发表于 10-13 10:47 621次阅读
    Spring 的<b class='flag-5'>线程</b><b class='flag-5'>池</b>应用

    如何设计一个线程JAVA线程是如何设计的?

    线程(thread)是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程的实际 运作单位。
    的头像 发表于 11-07 09:12 1666次阅读
    如何设计一个<b class='flag-5'>线程</b><b class='flag-5'>池</b>?<b class='flag-5'>JAVA</b><b class='flag-5'>中</b>的<b class='flag-5'>线程</b><b class='flag-5'>池</b>是如何设计的?

    线程基本概念与原理

    一、线程基本概念与原理 1.1 线程概念及优势 C++线程简介
    的头像 发表于 11-10 10:24 532次阅读

    线程的基本概念

    ? 呃呃,我这么问就很奇怪,因为线程是什么我都没说,怎么会知道为什么会有线程呢?所以我打算带大家去思考一个场景: 当我们的程序:有一批
    的头像 发表于 11-10 16:37 523次阅读
    <b class='flag-5'>线程</b><b class='flag-5'>池</b>的基本概念

    线程的运转流程图 化技术实践案例解析

    作为一名Java开发人员,化技术或多或少在业务代码中使用。常见的包括线程、连接等。也是因为
    的头像 发表于 11-24 10:22 467次阅读
    <b class='flag-5'>线程</b><b class='flag-5'>池</b>的运转流程图 <b class='flag-5'>池</b>化技术实践案例解析

    线程的创建方式有几种

    线程是一种用于管理和调度线程的技术,能够有效地提高系统的性能和资源利用率。它通过预先创建一组线程并维护一个工作队列,将任务提交给线程
    的头像 发表于 12-04 16:52 860次阅读

    什么是动态线程?动态线程的简单实现思路

    因此,动态可监控线程一种针对以上痛点开发的线程管理工具。主要可实现功能有:提供对 Spring 应用内线程
    的头像 发表于 02-28 10:42 642次阅读

    java实现多线程的几种方式

    了多种实现多线程的方式,本文将详细介绍以下几种方式: 1.继承Thread类 2.实现Runnable接口 3.Callable和Future 4.线程 5.Java 8
    的头像 发表于 03-14 16:55 697次阅读