一:前言

一个问题引出的学习笔记
并发类库提供的线程池实现有哪些?
其实Executors已经为我们封装好了 4 种常见的功能线程池,如下:

  • 定长线程池(FixedThreadPool)
  • 定时线程池(ScheduledThreadPool )
  • 可缓存线程池(CachedThreadPool)
  • 单线程化线程池(SingleThreadExecutor)

那么接下来就复习一波线程和线程池

二:线程

1:关于线程的理解

  • 自我理解:(这是在javaweb中的文件上传部分 实际用到的线程 来帮助理解线程)
    一个线程就是一条执行路径 ,实际例子当中 我们请求一个页面如果需要很长的时间的话,这时候我们需要设置线程来执行 请求消息中的代码,然后再写一个代码先显示出请求等待的信息
  • 官方解读:
    线程,程序执行流的最小执行单位,是行程中的实际运作单位,经常容易和进程这个概念混淆。那么,线程和进程究竟有什么区别呢?首先,进程是一个动态的过程,是一个活动的实体。简单来说,一个应用程序的运行就可以被看做是一个进程,而线程,是运行中的实际的任务执行者。可以说,进程中包含了多个可以同时运行的线程。

2:线程的声明周期

线程的生命周期,线程的生命周期可以利用以下的图解来更好的理解:

3:单线程和多线程

三:线程池

1:线程池从何处而来

  • 在一个应用程序中,我们需要多次使用线程,也就意味着,我们需要多次创建并销毁线程。而创建并销毁线程的过程势必会消耗内存。而在Java中,内存资源是及其宝贵的,所以,我们就提出了线程池的概念
    线程池:Java中开辟出了一种管理线程的概念,这个概念叫做线程池,从概念以及应用场景中,我们可以看出,线程池的好处,就是可以方便的管理线程,也可以减少内存的消耗。

2:线程池的好处

  • (1) 降低资源消耗。 通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
  • (2) 提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
  • (3) 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

3:如何实现线程池

那么,我们应该如何创建一个线程池那?Java中已经提供了创建线程池的一个类:Executor类,而我们创建时,一般使用它的子类:ThreadPoolExecutor.
线程池的真正实现类是 ThreadPoolExecutor,其构造方法有如下4种:

public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue) {this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,Executors.defaultThreadFactory(), defaultHandler);
}public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory) {this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,threadFactory, defaultHandler);
}public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler) {this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,Executors.defaultThreadFactory(), handler);
}public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) {if (corePoolSize < 0 ||maximumPoolSize <= 0 ||maximumPoolSize < corePoolSize ||keepAliveTime < 0)throw new IllegalArgumentException();if (workQueue == null || threadFactory == null || handler == null)throw new NullPointerException();this.corePoolSize = corePoolSize;this.maximumPoolSize = maximumPoolSize;this.workQueue = workQueue;this.keepAliveTime = unit.toNanos(keepAliveTime);this.threadFactory = threadFactory;this.handler = handler;
}

4:线程池的使用流程

// 创建线程池
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(CORE_POOL_SIZE,MAXIMUM_POOL_SIZE,KEEP_ALIVE,TimeUnit.SECONDS,sPoolWorkQueue,sThreadFactory);
// 向线程池提交任务
threadPool.execute(new Runnable() {@Overridepublic void run() {... // 线程执行的任务}
});
// 关闭线程池
threadPool.shutdown(); // 设置线程池的状态为SHUTDOWN,然后中断所有没有正在执行任务的线程
threadPool.shutdownNow(); // 设置线程池的状态为 STOP,然后尝试停止所有的正在执行或暂停任务的线程,并返回等待执行任务的列表

5:线程池的工作原理

6:线程池的重要参数解读

(1):任务队列

(2):线程工厂(threadFactory)

线程工厂指定创建线程的方式,需要实现 ThreadFactory 接口,并实现 newThread(Runnable r) 方法。该参数可以不用指定,Executors 框架已经为我们实现了一个默认的线程工厂:

(3):拒绝策略(handler)

7:功能性线程池

嫌上面使用线程池的方法太麻烦?其实Executors已经为我们封装好了 4 种常见的功能线程池,如下:

  • 定长线程池(FixedThreadPool)
  • 定时线程池(ScheduledThreadPool )
  • 可缓存线程池(CachedThreadPool)
  • 单线程化线程池(SingleThreadExecutor)
  • newWorkStealingPool

(1): newFixedThreadPool (固定数量的线程池)

创建的源码:

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);
}
  • 特点:只有核心线程,线程数量固定,执行完立即回收,任务队列为链表结构的有界队列。
  • 应用场景:控制线程最大并发数。
  • 使用实例:
// 1. 创建定长线程池对象 & 设置线程池线程数量固定为3
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
// 2. 创建好Runnable类线程对象 & 需执行的任务
Runnable task =new Runnable(){public void run() {System.out.println("执行任务啦");}
};
// 3. 向线程池提交任务
fixedThreadPool.execute(task);

(2): newWorkStealingPool


这个线程池的特性从名字就可以看出 Stealing,会窃取任务。
每个线程都有自己的双端队列,当自己队列的任务处理完毕之后,会去别的线程的任务队列尾部拿任务来执行,加快任务的执行速率。
至于 ForkJoin 的话,就是分而治之,把大任务分解成一个个小任务,然后分配执行之后再总和结果,

(3): newSingleThreadExecutor (单线程池)

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));
}

特点:只有 1 个核心线程,无非核心线程,执行完立即回收,任务队列为链表结构的有界队列。
应用场景:不适合并发但可能引起 IO 阻塞性及影响 UI 线程响应的操作,如数据库操作、文件操作等。
使用实例:

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));
}

(4):newCachedThreadPool (可缓存的线程池)

创建方法的源码:

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);
}

特点:无核心线程,非核心线程数量无限,执行完闲置 60s 后回收,任务队列为不存储元素的阻塞队列。
应用场景:执行大量、耗时少的任务。

所以它适合用在短时间内有大量短任务的场景。如果暂无可用线程,那么来个任务就会新启一个线程去执行这个任务,快速响应任务。
但是如果任务的时间很长,那存在的线程就很多,上下文切换就很频繁,切换的消耗就很明显,并且存在太多线程在内存中,也有 OOM 的风险。
使用示例:

// 1. 创建可缓存线程池对象
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
// 2. 创建好Runnable类线程对象 & 需执行的任务
Runnable task =new Runnable(){public void run() {System.out.println("执行任务啦");}
};
// 3. 向线程池提交任务
cachedThreadPool.execute(task);

(5): newScheduledThreadPool(定时线程池)

创建方法的源码: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);
}

特点:核心线程数量固定,非核心线程数量无限,执行完闲置 10ms 后回收,任务队列为延时阻塞队列。
应用场景:执行定时或周期性的任务。
使用示例:

/ 1. 创建 定时线程池对象 & 设置线程池线程数量固定为5
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
// 2. 创建好Runnable类线程对象 & 需执行的任务
Runnable task =new Runnable(){public void run() {System.out.println("执行任务啦");}
};
// 3. 向线程池提交任务
scheduledThreadPool.schedule(task, 1, TimeUnit.SECONDS); // 延迟1s后执行任务
scheduledThreadPool.scheduleAtFixedRate(task,10,1000,TimeUnit.MILLISECONDS);// 延迟10ms后、每隔1000ms执行任务

参考自这篇博客

线程与线程池(一条龙详解)相关推荐

  1. async spring 默认线程池_Spring boot注解@Async线程池实例详解

    这篇文章主要介绍了Spring boot注解@Async线程池实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 从Spring3开始提供了@A ...

  2. python线程池原理_Python定时器线程池原理详解

    这篇文章主要介绍了Python定时器线程池原理详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 定时器执行循环任务: 知识储备 Timer(int ...

  3. 线程池源代码详解,参数详解

    线程池源代码详解,参数详解 ThreadPoolExecutor 构造函数源代码 public ThreadPoolExecutor(int corePoolSize, int maximumPool ...

  4. Java线程池ThreadPool详解

    Java线程池ThreadPool详解 1. 线程池概述 1.1 线程池简介 1.2 线程池特点 1.3 线程池解决问题 2. 线程池原理分析 2.1 线程池总体设计 2.6 线程池流转状态 2.2 ...

  5. java condition详解_Java使用Condition控制线程通信的方法实例详解

    Java使用Condition控制线程通信的方法实例详解 发布于 2020-4-20| 复制链接 摘记: 本文实例讲述了Java使用Condition控制线程通信的方法.分享给大家供大家参考,具体如下 ...

  6. wxpython多线程 假死_wxpython多线程防假死与线程间传递消息实例详解

    wxpython中启用线程的方法,将GUI和功能的执行分开. 网上关于python多线程防假死与线程传递消息是几年前的,这里由于wxpython和threading模块已经更新最新,因此给出最新修改代 ...

  7. Java 解析线程的几种状态详解

    Java 解析线程的几种状态详解 1. 线程的5种状态 从操作系统层面上,任何线程一般都具有五种状态,即创建.就绪.运行.阻塞.终止. (1) 新建状态(NEW) 在程序中用构造方法创建一个新线程时, ...

  8. jdbc 连接池 java_JDBC自定义连接池过程详解

    这篇文章主要介绍了JDBC自定义连接池过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 开发中,"获得连接"和" ...

  9. Spring Boot 使用 HikariCP 连接池配置详解

    Spring Boot 使用 HikariCP 连接池配置详解 HikariCP 是一个高性能的 JDBC 连接池组件. Spring Boot 2.x 将其作为默认的连接池组件,项目中添加 spri ...

  10. Hikari连接池配置详解

    Hikari连接池配置详解 ## 数据库配置 spring.datasource.type=com.zaxxer.hikari.HikariDataSource spring.datasource.d ...

最新文章

  1. EMQ学习笔记---Clean Session和Retained Message
  2. spring boot 第三讲
  3. cdoj 秋实大哥搞算数
  4. 企业实战(Jenkins+GitLab+SonarQube)_08_jenkins安装和第一个Java项目构建
  5. XXE漏洞利用技巧(XML注入):从XML到远程代码执行
  6. 创新创业大讲堂第一讲
  7. 用Java实现HTTP文件队列下载
  8. c语言从excal读取字符串,C语言操作EXCEL文件(读写)
  9. 软件是怎么开发出来的?怎么进行软件开发流程
  10. js replace 中文分号_关于js分号的问题?
  11. 《追寻生命的意义》摘抄
  12. word文档没保存就关了怎么恢复?别慌!试试这个操作
  13. 大数据会给我们带来什么影响?
  14. 期货、股票行情、交易源码
  15. 洛谷 魔法少女 python
  16. 无法写入最后一个_香港影史无法超越的25个惊艳瞬间,最后一个还是双黄蛋
  17. win7注册表关闭防火墙服务器,怎么样修改注册表来关闭windows防火墙?
  18. C++输入角度计算三角函数cos sin tan
  19. 2022 蓝桥杯C语言B组
  20. My programs (我写的软件)

热门文章

  1. mysql一张表最多多少索引_MySQL一个索引最多有多少个列?真实的测试例子
  2. 遍历文件夹还原数据库SQL语句
  3. ArcGIS实验教程——实验三:矢量数据采集与编辑(矢量化)
  4. Android之gravity=“center_vertical“和layout_gravity=“center“的效果
  5. Android之非root手机run-as命令获取debug版本apk里面的数据(shared_prefs文件,lib下面的so,数据库文件)
  6. React Native之提示Unable to load script from assets ‘index.android.bundle
  7. Android之HandlerThread源码分析和简单使用(主线程和子线程通信、子线程和子线程通信)
  8. LeetCode之Relative Ranks
  9. java多进程、多线程讲解
  10. 因为没钱买衣服,我女朋友不要我了......