IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 深耕Java多线程 - 什么是线程池?优点?线程池有哪几种创建方式? -> 正文阅读

[Java知识库]深耕Java多线程 - 什么是线程池?优点?线程池有哪几种创建方式?

问题思考:

1、什么是线程池?
2、线程池有什么优点?
3、线程池有哪几种创建方式?
4、Executors和ThreaPoolExecutor创建线程池的区别?
5、你知道怎么创建线程池吗?

1. 线程池有什么优点?

Java高并发应用频繁创建和销毁线程的操作是非常低效的,而且是不被编程规范所允许的。如何降低Java线程的创建成本?必须使用到线程池。线程池主要解决了以下两个问题:

(1)提升性能:线程池能独立负责线程的创建、维护和分配。在执行大量异步任务时,可以不需要自己创建线程,而是将任务交给线程池去调度。线程池能尽可能使用空闲的线程去执行异步任务,最大限度地对已经创建的线程进行复用,使得性能提升明显。

(2)线程管理:每个Java线程池会保持一些基本的线程统计信息,例如完成的任务数量、空闲时间等,以便对线程进行有效管理,使得能对所接收到的异步任务进行高效调度。

在主要大厂的编程规范中,不允许在应用中自行显式地创建线程,线程必须通过线程池提供。由于创建和销毁线程需要时间以及系统资源开销,使用线程池的好处是减少这些开销,解决资源不足的问题。

2. 什么是线程池?

在多线程编程中,任务都是一些抽象且离散的工作单元,而线程是使任务异步执行的基本机制。随着应用的扩张,线程和任务管理也变得非常复杂。为了简化这些复杂的线程管理模式,我们需要一个“管理者”来统一管理线程及任务分配,这就是线程池。

在JUC中有关线程池的类与接口的架构图大致如图:
在这里插入图片描述

1. Executor

Executor是Java异步目标任务的“执行者”接口,其目标是执行目标任务。“执行者”Executor提供了execute()方法来执行已提交的Runnable执行目标实例。它只包含一个函数式方法:

public interface Executor {
    void execute(Runnable command);
}

2. ExecutorService

ExecutorService继承于ExecutorExecutorService提供了“接收异步任务并转交给执行者”的方法,如submit系列方法、invoke系列方法等,具体如下:

public interface ExecutorService extends Executor {
	// 向线程池提交单个异步任务
    <T> Future<T> submit(Callable<T> task);
    Future<?> submit(Runnable task);
    
	// 向线程池提交批量异步任务
    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException;
    // 其他方法.....
}

3. AbstractExecutorService

AbstractExecutorService是一个抽象类,它实现了ExecutorService接口。AbstractExecutorService存在的目的是为ExecutorService中的接口提供默认实现。

4. ThreadPoolExecutor

ThreadPoolExecutor就是大名鼎鼎的“线程池”实现类,它继承于AbstractExecutorService抽象类。ThreadPoolExecutor是JUC线程池的核心实现类。线程的创建和终止需要很大的开销,线程池中预先提供了指定数量的可重用线程,所以使用线程池会节省系统资源,并且每个线程池都维护了一些基础的数据统计,方便线程的管理和监控。

5. ScheduledExecutorService

ScheduledExecutorService是一个接口,它继承于ExecutorService。它是一个可以完成“延时”和“周期性”任务的调度线程池接口,其功能和Timer/TimerTask类似。

6. ScheduledThreadPoolExecutor

ScheduledThreadPoolExecutor继承于ThreadPoolExecutor,它提供了ScheduledExecutorService线程池接口中“延时执行”和“周期执行”等抽象调度方法的具体实现。ScheduledThreadPoolExecutor类似于Timer,但是在高并发程序中,ScheduledThreadPoolExecutor的性能要优于Timer

7. Executors

Executors是一个静态工厂类,它通过静态工厂方法返回ExecutorService、ScheduledExecutorService等线程池示例对象,这些静态工厂方法可以理解为一些快捷的创建线程池的方法。

3. Executors的4种快捷创建线程池的方法

Java通过Executors工厂类提供了4种快捷创建线程池的方法:

public class Executors {
    // 创建只有一个线程的线程池
    public static ExecutorService newSingleThreadExecutor() {
        // 底层调用了ThreadPoolExecutor的构造方法
        return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }
    
    // 创建固定大小的线程池
    public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
        // 底层调用了ThreadPoolExecutor的构造方法
        return new ThreadPoolExecutor(nThreads, nThreads,
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>(),
                                      threadFactory);
    }
       
    // 创建一个不限制线程数量的线程池,任何提交的任务都将立即执行,但是空闲线程会得到及时回收
    public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
        // 底层调用了ThreadPoolExecutor的构造方法
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>(),
                                      threadFactory);
    }
	
    // 创建一个可定期或者延时执行任务的线程池
    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory) {
        // 底层调用了ScheduledThreadPoolExecutor的构造方法
        return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
    }
}
Executors静态工厂类中的方法名功能简介
newSingleThreadExecutor ()创建只有一个线程的线程池
newFixedThreadPool (nThreads)创建固定大小的线程池
newCachedThreadPool()创建一个不限制线程数量的线程池,任何提交的任务都将立即执行,但是空闲线程会得到及时回收
newScheduledThreadPool()创建一个可定期或者延时执行任务的线程池

以上为Executors中4个主要的快捷创建线程池的方法。为何JUC要提供工厂方法呢?原因是使用ThreadPoolExecutor ScheduledThreadPoolExecutor构造器创建普通线程池、可调度线程池比较复杂,这些构造器会涉及大量的复杂参数。尽管Executors的工厂方法使用方便,但是在生产场景中被很多企业(尤其是大厂)的开发规范所禁用。

4. 线程池的标准创建方式

大部分企业的开发规范都会禁止使用快捷线程池,要求通过标准构造器ThreadPoolExecutor去构造工作线程池。Executors工厂类中创建线程池的快捷工厂方法实际上是调用ThreadPoolExecutor(定时任务使用ScheduledThreadPoolExecutor)线程池的构造方法完成的。

ThreadPoolExecutor构造方法有多个重载版本,其中一个比较重要的构造器如下:

/**
 * 使用标准构造器构造一个普通的线程池
 *
 * @param corePoolSize  核心线程数,即使线程空闲,也不会回收
 * @param maximumPoolSize  线程数的上限(最大线程数)
 * @param keepAliveTime  线程最大空闲时间(线程的生存时间)
 * @param unit 时间单位
 * @param workQueue 任务的排队队列
 * @param threadFactory 新线程的产生方式
 * @param handler 拒绝策略
 */
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler)

很无奈,构造一个线程池竟然有7个参数,但是确实需要这么多参数。

1. 核心和最大线程数量

参数corePoolSize用于设置核心线程池数量,参数maximumPoolSize用于设置最大线程数量。线程池执行器将会根据corePoolSize和maximumPoolSize自动维护线程池中的工作线程,大致规则为:

(1)当在线程池接收到新任务,并且当前工作线程数少于corePoolSize时,即使其他工作线程处于空闲状态,也会创建一个新线程来处理该请求,直到线程数达到corePoolSize。

(2)如果当前工作线程数多于corePoolSize数量,但小于maximumPoolSize数量,那么仅当任务排队队列已满时才会创建新线程。通过设置corePoolSize和maximumPoolSize相同,可以创建一个固定大小的线程池。

(3)当maximumPoolSize被设置为无界值(如Integer.MAX_VALUE)时,线程池可以接收任意数量的并发任务。

(4)corePoolSize和maximumPoolSize不仅能在线程池构造时设置,也可以调用setCorePoolSize()和setMaximumPoolSize()两个方法进行动态更改。

2. BlockingQueue

BlockingQueue(阻塞队列)的实例用于暂存接收到的异步任务,如果线程池的核心线程都在忙,那么所接收到的目标任务缓存在阻塞队列中。

3. keepAliveTime

线程构造器的keepAliveTime(空闲线程存活时间)参数用于设置池内线程最大Idle(空闲)时长,如果超过这个时间,默认情况下Idle、非Core线程会被回收。

如果池在使用过程中提交任务的频率变高,也可以调用方法setKeepAliveTime(long,TimeUnit)进行线程存活时间的动态调整,可以将时长延长。如果需要防止Idle线程被终止,可以将Idle时间设置为无限大,具体如下:

setKeepAliveTime(Long.MAX_VALUE,TimeUnit.NANOSECONDS);

默认情况下,Idle超时策略仅适用于存在超过corePoolSize线程的情况。但若调用了allowCoreThreadTimeOut(boolean)方法,并且传入了参数true,则keepAliveTime参数所设置的Idle超时策略也将被应用于核心线程。

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-03-08 22:14:58  更:2022-03-08 22:15:41 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 11:24:49-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码