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

    文章

    7639

    浏览量

    148495
  • JAVA
    +关注

    关注

    19

    文章

    2904

    浏览量

    102994
  • 管理器
    +关注

    关注

    0

    文章

    233

    浏览量

    18318
  • 函数
    +关注

    关注

    3

    文章

    3868

    浏览量

    61309
  • 线程池
    +关注

    关注

    0

    文章

    53

    浏览量

    6768
收藏 人收藏

    评论

    相关推荐

    Java线程的用法

    本文将介绍一下Java线程的用法。 基础介绍 什么是多线程 指的是在一个进程中同时运行多个线程,每个线程都可以独立执行不同的任务或操作。
    的头像 发表于 09-30 17:07 622次阅读

    Java工程师必须掌握的技术有哪些?

    start一个线程会怎么样、线程有哪些状态。另外,线程也是比较常问的一块,常用的线程有几种?
    发表于 02-09 16:18

    Java线程阻塞方法大全

    IO是操作系统实现的,Java代码并没有办法直接接触到操作系统。以下是详细的唤醒方法:1. sleep() 方法sleep(毫秒),指定以毫秒为单位的时间,使线程在该时间内进入线程阻塞状态,期间得不到
    发表于 04-02 15:42

    Java守护线程和本地线程的区别

    java线程分为两种:守护线程(Daemon)和用户线程(User)。
    发表于 08-07 08:10

    java】两种方式实现线程通信:三个线程交替打印AABBCC

    ()、signal()方法。使用wait/notify进行线程通信只能够随机唤醒,增加了上下文的切换时间,使用await/signal可以实现精准唤醒,java集合框架的队列就采用了后者实现
    发表于 09-20 16:38

    线程是如何实现的

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

    线程创建的两种方法

    ,让过来的任务立刻能够使用,就形成了线程。在Python3,创建线程是通过concurr
    发表于 03-16 16:15

    关于RT-Thread内存管理的内存简析

    链表上,并增加内存可用内存块的数目。在释放过程,会判断该内存对象上是否有挂起线程,若有,则唤醒挂起线程链表上第一个
    发表于 04-06 17:02

    java线程设计模式_结城浩

    JAVA线程设计模式》通过浅显易懂的文字与实例来介绍JAVA线程相关的设计模式概念,并且通过实际的JAVA程序范例和UML图示来一一解说
    发表于 01-05 16:15 0次下载
    <b class='flag-5'>java</b>多<b class='flag-5'>线程</b>设计模式_结城浩

    java学习——java面试【事务、锁、多线程】资料整理

    本文档内容介绍了基于java学习java面试【事务、锁、多线程】资料整理,供参考
    发表于 03-13 13:53 0次下载

    Java教程之零点起飞学Java线程资料说明

    线程编程是提高应用程序性能的重要手段之一。Java平台从开始就被设计成为多线程环境,从语言级上支持多线程。在Java语言中,提供了创建、启
    发表于 02-20 10:41 3次下载
    <b class='flag-5'>Java</b>教程之零点起飞学<b class='flag-5'>Java</b>的<b class='flag-5'>线程</b>资料说明

    java定时器和多线程

    完成一个java application应用程序,在应用程序主进程中新开一个线程,此线程进行死循环,每1秒被激活一次,激活时即在输出显示当前时间。
    发表于 06-17 14:11 2607次阅读
    <b class='flag-5'>java</b>定时器和多<b class='flag-5'>线程</b>

    为什么Java线程没有Running状态?

    什么是 RUNNABLE? 与传统的ready状态的区别 与传统的running状态的区别 当I/O阻塞时 如何看待RUNNABLE状态? Java虚拟机层面所暴露给我们的状态,与操作系统底层的线程
    的头像 发表于 06-17 17:36 1270次阅读

    Java线程池核心原理

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

    java实现多线程的几种方式

    Java实现多线程的几种方式 多线程是指程序中包含了两个或以上的线程,每个线程都可以并行执行不同的任务或操作。
    的头像 发表于 03-14 16:55 176次阅读