使用自定义的方式创建线程池

Java本身提供的获取线程池的方式

使用Executors直接获取线程池,注意,前四个方式的底层都是通过new ThreadPoolExecutor()的方式创建的线程池,只是参数不一样而已,我们也正是利用了这点特性来实现自己的线程池

1. newCachedThreadPool

创建一个可缓存无限制数量的线程池,
如果线程池中没有空闲的线程的话,再来任务会新建线程,
线程60s内没被使用,则销毁。
简单的说,忙不过来的时候就新建线程 Executors.newCachedThreadPool() 底层实现
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
} 常驻核心线程数为0
线程池最大线程数Integer.MAX_VALUE
线程空闲60S回收
使用工作队列来存放任务,这个队列有好几种,各有各的特性。
**风险:**由于线程池最大线程池为Integer.MAX_VALUE,所以有OOM的风险

2. newFixedThreadPool

创建一直指定大小的线程池,如果线程池满了,后面的任务会在队列中等待,等拿到空闲的线程才能执行

Executors.newFixedThreadPool(nThreads)

底层实现
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
} 常驻核心线程数自定义
线程池最大线程数等于常驻核心线程数
因为最大线程数等于常驻核心线程,而常驻核心线程不会被回收,所以时间参数为0
使用工作队列来存放任务,这个队列有好几种,各有各的特性。
**风险:**由于队列没有指明长度,默认为Integer.MAX_VALUE,所以有OOM的风险

3. newSingleThreadExecutor

创建一个大小为1的线程池,用唯一的线程来执行任务,保证任务有序进行

Executors.newSingleThreadExecutor()

底层实现
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
} 常驻核心线程数为1
线程池最大线程数等于常驻核心线程数1
线程池里一共就一个常驻核心线程,所以不会被回收,所以时间参数为0
使用工作队列来存放任务,这个队列有好几种,各有各的特性。
**风险:**由于队列没有指明长度,默认为Integer.MAX_VALUE,所以有OOM的风险

4. newScheduledThreadPool

创建指定大小的线程池,支持定时及周期性的执行任务

Executors.newScheduledThreadPool(corePoolSize)

底层实现
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
} ScheduledThreadPoolExecutor继承了ThreadPoolExecutor,一下为ScheduledThreadPoolExecutor的构造方法 public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
} 常驻核心线程数自定义
线程池最大线程数等于Integer.MAX_VALUE
不回收线程
使用工作队列来存放任务,这个队列有好几种,各有各的特性。
**风险:**由于线程池最大线程池为Integer.MAX_VALUE,所以有OOM的风险

5. newWorkStealingPool

JDK1.8 引入
创建持有足够线程的线程池来支持给定的并行级别,
并通过使用多个队列减少竞争,并行级别的参数,如果不传,默认为cpu的数量,
返回的不再是 ThreadPoolExecutor 而是 ForkJoinPool Executors.newWorkStealingPool() 底层实现为**ForkJoinPool**,和上面的四个不同
public static ExecutorService newWorkStealingPool() {
return new ForkJoinPool
(Runtime.getRuntime().availableProcessors(),
ForkJoinPool.defaultForkJoinWorkerThreadFactory,
null, true);
} 正在研究ing

在阿里巴巴Java开发手册中明确指出,不允许使用jdk自带的方式获取线程池。就是上面的前四个方法,所以,我们自己创建即可

创建自定义的线程工厂

public class ThreadFactoryImpl implements ThreadFactory {
/**
* 线程池号
*/
private static final AtomicInteger poolNumber = new AtomicInteger(1);
/**
* 线程前缀名称
*/
private final String namePrefix;
/**
* 创建初始值为1且线程安全的线程号
*/
private final AtomicInteger threadNumber = new AtomicInteger(1); public ThreadFactoryImpl(String whatFeatureOfGroup) {
namePrefix = "ThreadFactoryImpl's " + whatFeatureOfGroup + "-work-";
} @Override
public Thread newThread(Runnable r) {
int threadNextId = threadNumber.getAndIncrement();
String name = namePrefix + threadNextId;
Thread thread = new Thread(null, r, name, 0);
System.out.println("创建的第"+threadNextId+"个线程");
return thread;
}
} AtomicInteger 实现了原子性,保证了高并发下的线程安全,该系类还有很多。
我们可以在自定义的线程工厂里面添加我们需要的内容
不指定的话,会是默认的线程工厂
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 static ThreadFactory defaultThreadFactory() {
return new DefaultThreadFactory();
}

创建自定义线程池拒绝策略

public class ThreadPoolRejectHandler implements RejectedExecutionHandler {

    @Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.out.println("task rejected. "+executor.toString());
}
} 在ThreadPoolExecutor中提供了四个公开的内部静态类
1. AbortPolicy(默认):丢弃任务并抛出RejectedExecutionException异常
2. DiscardPloicy:丢弃任务,不抛出异常(不推荐使用)
3. DiscardOldestPolicy:丢弃队列中等待最久的任务,把当前任务加入到队列中
4. CallerRunsPolicy:绕过线程池,直接调用任务的run()方法。
**根据需求选中合适的策略才是正确的**

实现我们的线程池

public class ThreadPoolUtil {

    /**
* @param corePoolSize 常驻核心线程,线程池初始化的时候池里是没有线程的,前面 corePoolSize 个任务是会创建线程,
* 当前线程池中的数量大于常驻核心线程数的时候,如果有空闲的线程则使用,没有的话就把任务放到
* 工作队列中
* @param maximumPoolSize 线程池允许创建的最大线程数,如果队列满了,且线程数小于最大线程数,则新建临时线程(空闲超过时间会被销毁的),
* 如果队列为无界队列,则该参数无用
* @param workQueueSize 工作队列,请求线程数大于常驻核心线程数的时候,将多余的任务放到工作队列
* @param threadName 线程名称
* @param handler 线程池拒绝策略,当线程池和队列都满了,则调用该策略,执行具体的逻辑
* @author: taoym
* @date: 2020/9/9 11:35
* @desc: 自定义线程池的实现 总体逻辑就是 前corePoolSize个任务时,来一个任务就创建一个线程
* 如果当前线程池的线程数大于了corePoolSize那么接下来再来的任务就会放入到我们上面设置的workQueue队列中
* 如果此时workQueue也满了,那么再来任务时,就会新建临时线程,那么此时如果我们设置了keepAliveTime或者设置了allowCoreThreadTimeOut,那么系统就会进行线程的活性检查,一旦超时便销毁线程
* 如果此时线程池中的当前线程大于了maximumPoolSize最大线程数,那么就会执行我们刚才设置的handler拒绝策略
*/
public static ExecutorService createThreadPool(int corePoolSize,
int maximumPoolSize,
int workQueueSize,
String threadName,
RejectedExecutionHandler handler) {
BlockingQueue workQueue = new LinkedBlockingDeque(workQueueSize);
ThreadFactoryImpl threadFactory = new ThreadFactoryImpl(threadName); ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, 60L, TimeUnit.SECONDS, workQueue, handler);
// 提前创建好核心线程
//threadPoolExecutor.prestartAllCoreThreads();
// 常驻核心线程的空闲时间超过 keepAliveTime 的时候要被回收
//threadPoolExecutor.allowCoreThreadTimeOut(true); return threadPoolExecutor;
}
} 注释写的很明白了,desc下的注释来自springForAll的文章。别的都是自己找的加上自己所理解的编写而成。

文章是刚研究了《码出高效》的线程池篇加上对源码文档的理解,趁热打铁写出来的,写的不好,多多见谅。

自定义线程池ThreadPoolExecutor的更多相关文章

  1. Executors提供的四种线程池和自定义线程池

    JAVA并发编程——EXECUTORS 线程池的思想是一种对象池的思想,开放一块内存空间,里面存放了众多(未死亡)的线程,池中线程执行调度由池管理器来处理.当有线程任务时,从池中取一个,执行完毕,对象 ...

  2. Android线程管理之ThreadPoolExecutor自定义线程池

    前言: 上篇主要介绍了使用线程池的好处以及ExecutorService接口,然后学习了通过Executors工厂类生成满足不同需求的简单线程池,但是有时候我们需要相对复杂的线程池的时候就需要我们自己 ...

  3. 基于ThreadPoolExecutor,自定义线程池简单实现

    一.线程池作用 在上一篇随笔中有提到多线程具有同一时刻处理多个任务的特点,即并行工作,因此多线程的用途非常广泛,特别在性能优化上显得尤为重要.然而,多线程处理消耗的时间包括创建线程时间T1.工作时间T ...

  4. 自定义线程池的名称(ThreadPoolExecutor)

    目的:有时候为了快速定位出现错误的位置,在采用线程池时我们需要自定义线程池的名称. 1.创建ThreadFactory(ThreadPoolExecutor默认采用的是DefaultThreadFac ...

  5. Android AsyncTask 深度理解、简单封装、任务队列分析、自定义线程池

    前言:由于最近在做SDK的功能,需要设计线程池.看了很多资料不知道从何开始着手,突然发现了AsyncTask有对线程池的封装,so,就拿它开刀,本文将从AsyncTask的基本用法,到简单的封装,再到 ...

  6. [转] 引用 Java自带的线程池ThreadPoolExecutor详细介绍说明和实例应用

    PS: Spring ThreadPoolTaskExecutor vs Java Executorservice cachedthreadpool 引用 [轰隆隆] 的 Java自带的线程池Thre ...

  7. JAVA并发,线程工厂及自定义线程池

    package com.xt.thinks21_2; import java.util.concurrent.ExecutorService; import java.util.concurrent. ...

  8. java多线程(四)-自定义线程池

    当我们使用 线程池的时候,可以使用 newCachedThreadPool()或者 newFixedThreadPool(int)等方法,其实我们深入到这些方法里面,就可以看到它们的是实现方式是这样的 ...

  9. SOFA 源码分析 — 自定义线程池原理

    前言 在 SOFA-RPC 的官方介绍里,介绍了自定义线程池,可以为指定服务设置一个独立的业务线程池,和 SOFARPC 自身的业务线程池是隔离的.多个服务可以共用一个独立的线程池. API使用方式如 ...

随机推荐

  1. LinuX操作系统基础------> 用户管理,grep搜索

    用户管理 用户组管理 字符管理和grep搜索 1.用户管理: LinuX是一个多用户,多任务的操作系统,可以让多个用户使用,这个账号可以帮助对用户进行追踪,必须在初始化的时候设置好自己的密码 1-1配 ...

  2. Weighted-Residual-Connections

  3. C#开发笔记之04-如何用C#优雅的计算个人所得税?

    C#开发笔记概述 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/960 访问. 首先,要对个人所得税的计算方式了解之后再 ...

  4. 将阿里矢量图添加到element-ui

    在阿里矢量图的操作 选择需要的图标添加至购物车   选择图标 将购物车中的图标, 添加至项目   添加至项目 会自动跳转到我的项目   项目页面 在 更多操作 中选择 编辑项目   更多操作 将 Fo ...

  5. 存储系列之 VFS虚拟文件系统简介

    引言:文件系统发展到一定阶段,开始进一步抽象和分层.   前面我们介绍了ext系列文件系统和xfs文件系统,这些是Linux使用最多的文件系统,也是很多发布版本默认选择的文件系统.而事实上,Linux ...

  6. 极简 Node.js 入门 - 2.4 定时器

    极简 Node.js 入门系列教程:https://www.yuque.com/sunluyong/node 本文更佳阅读体验:https://www.yuque.com/sunluyong/node ...

  7. 悄咪咪提高团队幸福感 & Surprise!

    前言 本文的灵感是在几个月以前工作不忙(摸鱼)时想到的,老是自己一个人往前冲冲冲也没啥意思,需要想一点办法,来提高团队的效率,提高团队的幸福感(效率起来了,单位时间内代码写的更多,那不就幸福啦 ),经 ...

  8. 二叉搜索树 [四边形不等式优化区间dp]

    二叉搜索树 [四边形不等式优化区间dp] 题目描述 有 \(n\) 个结点,第 \(i\) 个结点的权值为 \(i\) . 你需要对它们进行一些操作并维护一些信息,因此,你需要对它们建立一棵二叉搜索树 ...

  9. web基础(四)严格模式与混杂模式

    web基础(四)严格模式与混杂模式 一.介绍 DOCTYPE 标签是一种标准通用标记语言的文档类型声明,它的目的是要告诉标准通用标记语言解析器,它应该使用什么样的文档类型定义(DTD)来解析文档.DO ...

  10. ElasticSearch实战系列八: Filebeat快速入门和使用---图文详解

    前言 本文主要介绍的是ELK日志系统中的Filebeat快速入门教程. ELK介绍 ELK是三个开源软件的缩写,分别表示:Elasticsearch , Logstash, Kibana , 它们都是 ...