手写线程池

Executors.newSingleThreadExecutor():

只有一个线程的线程池,因此所有提交的任务是顺序执行

Executors.newCachedThreadPool():

线程池里有很多线程需要同时执行,老的可用线程将被新的任务触发重新执行,

如果线程超过60秒内没执行,那么将被终止并从池中删除

Executors.newFixedThreadPool():

拥有固定线程数的线程池,如果没有任务执行,那么线程会一直等待

Executors.newScheduledThreadPool():

用来调度即将执行的任务的线程池

Executors.newWorkStealingPool():

newWorkStealingPool适合使用在很耗时的操作,

但是newWorkStealingPool不是ThreadPoolExecutor的扩展,

它是新的线程池类ForkJoinPool的扩展,但是都是在统一的一个Executors类中实现,

由于能够合理的使用CPU进行对任务操作(并行操作),所以适合使用在很耗时的任务中

生产环境不使用以上线程池,主要原因是,以上线程池底层使用的LinkedBlockingQueue链表阻塞

队列,这样最大值为21亿,范围过大,会造成OOM异常。

需要使用ThreadPoolExecutor传递7个参数手工实现线程池。

ThreadPoolExecutor

ThreadPoolExecutor作为java.util.concurrent包对外提供基础实现,以内部线程池的形式对外提供管理任务执行,

线程调度,线程池管理等等服务。

corePoolSize 核心线程池大小
maximumPoolSize 最大线程池大小
keepAliveTime 线程池中超过 corePoolSize 数目的空闲线程最大存活时间;可以allowCoreThreadTimeOut(true) 使得核心线程有效时间
TimeUnit keepAliveTime 时间单位
workQueue 阻塞任务队列
threadFactory 新建线程工厂
RejectedExecutionHandler 当提交任务数超过 maxmumPoolSize+workQueue 之和时,任务会交给RejectedExecutionHandler 来处理

Java中的BlockingQueue主要有两种实现,分别是ArrayBlockingQueue 和 LinkedBlockingQueue。

ArrayBlockingQueue是一个用数组实现的有界阻塞队列,必须设置容量。

LinkedBlockingQueue是一个用链表实现的有界阻塞队列,容量可以选择进行设置,

不设置的话,将是一个无边界的阻塞队列,最大长度为Integer.MAX_VALUE。

这里的问题就出在:不设置的话,将是一个无边界的阻塞队列,最大长度为Integer.MAX_VALUE。

也就是说,如果我们不设置LinkedBlockingQueue的容量的话,其默认容量将会是Integer.MAX_VALUE。

=================测试===============================================

package t1;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TestExecutors {

public static void main(String[] args) {
ExecutorService executorService = new ThreadPoolExecutor(2, // corePoolSize 当日值班线程
5, // maximumPoolSize  最大可提供线程
1, // keepAliveTime  除开值班线程等待时间,等待这么多时间后,除开值班线程的其他线程销毁
TimeUnit.SECONDS, // unit  等待时间的单位 ,等待这么多时间后,除开值班线程的其他线程销毁
new LinkedBlockingDeque<>(3), // workQueue  阻塞队列的类型以及大小
Executors.defaultThreadFactory(), // threadFactory 配置 默认即可
new ThreadPoolExecutor.AbortPolicy());// handler 线程多于maximumPoolSize+LinkedBlockingDeque后会报错

// new ThreadPoolExecutor.CallerRunsPolicy());//handler 多的交给调用他的线程处理
// new ThreadPoolExecutor.DiscardOldestPolicy());//handler 丢掉等待最久的线程
// new ThreadPoolExecutor.DiscardPolicy());//handler 丢掉处理不过来的线程

for (int i = 0; i < 9; i++) {
executorService.execute(() -> {
System.out.println(Thread.currentThread().getName());

});

}
}

}

输出结果根据拒绝策略而异。

*********************************************************

corePoolSize 参数配置规则

CPU 密集型:比如while循环一开,CPU就很高上去了这种

CPU 密集的意思是该任务需要大量的运算,而没有阻塞,CPU 一直全速运行。

CPU 密集型任务尽可能的少的线程数量,一般为 CPU 核数 + 1 个线程的线程池。

IO 密集型:比如磁盘IO特别频繁这种

由于 IO 密集型任务线程并不是一直在执行任务,可以多分配一点线程数,如 CPU * 2 。

也可以使用公式:CPU 核数 / (1 - 阻塞系数);其中阻塞系数在 0.8 ~ 0.9 之间。

原文地址:https://www.cnblogs.com/dengw125792/p/12630190.html

时间: 2024-07-31 22:55:31

手写线程池的相关文章

手写线程池 (一)

前言准备 1.jdk线程池的使用:https://www.cnblogs.com/jtfr/p/10187419.html 2.线程池核心:线程的复用. 运行的线程是线程池的核心,被添加的任务需要实现过Runnable接口,主要是保证有run方法.运行时候 对象.run() . 一.手写线程池注意要点 1.线程池需要添加任务,任务是放置在一个队列(FIFO)当中,具体只要保证FIFO,或优先级保证(Map集合)先执行.2.线程池运行,需要一个容器存放创建的线程,可数组或集合,可以自己设计思考.3

图解线程池工作机制,手写线程池?

ThreadPoolExecutor构造函数的各个参数说明 public ThreadPoolExecutor(int corePoolSize,//线程池中核心线程数 int maximumPoolSize,//允许的最大线程数 long keepAliveTime,//线程空闲下来后,存活的时间,这个参数只在> corePoolSize才有用 TimeUnit unit,//存活时间的单位值 BlockingQueue<Runnable> workQueue,//保存任务的阻塞队列

手写数据库连接池

  1.  相信很多人看这篇文章已经知道连接池是用来干什么的?没错,数据库连接池就是为数据库连接建立一个"缓冲池",预先在"缓冲池"中放入一定数量的连接欸,当需要建立数据库连接时,从"缓冲池"中取出一个,使用完毕后再放进去.这样的好处是,可以避免频繁的进行数据库连接占用很多的系统资源.      2.  常见的数据库连接池有:dbcp,c3p0,阿里的Druid.好了,闲话不多说,本篇文章旨在加深大家对连接池的理解.这里我选用的数据库是mysql

手写连接池

4.连接池_手写连接池_动态代理 二.数据库连接池 很多很多的连接 放进一个池子里用集合来存取这些连接 手写连接池: 改造conn的close方法 1.继承 2.装饰 3.动态代理 package com.itheima.pool; import java.io.PrintWriter; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Pro

自己动手写线程池

一.线程池源码如下 1.阻塞任务队列 BlockingQueue public interface BlockingQueue<E> { boolean offer(E e); public E take();} 阻塞任务队列实现类  LinkedBlockingQueue import java.util.concurrent.atomic.AtomicInteger; public class LinkedBlockingQueue<E> implements Blocking

关于利用动态代理手写数据库连接池的异常 java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to java.sql.Connection

代码如下: final Connection conn=pool.remove(0); //利用动态代理改造close方法 Connection proxy= (Connection) Proxy.newProxyInstance(conn.getClass().getClassLoader(), conn.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object pro

死磕 java线程系列之自己动手写一个线程池(续)

(手机横屏看源码更方便) 问题 (1)自己动手写的线程池如何支持带返回值的任务呢? (2)如果任务执行的过程中抛出异常了该怎么处理呢? 简介 上一章我们自己动手写了一个线程池,但是它是不支持带返回值的任务的,那么,我们自己能否实现呢?必须可以,今天我们就一起来实现带返回值任务的线程池. 前情回顾 首先,让我们先回顾一下上一章写的线程池: (1)它包含四个要素:核心线程数.最大线程数.任务队列.拒绝策略: (2)它具有执行无返回值任务的能力: (3)它无法处理有返回值的任务: (4)它无法处理任务

线程池ThreadPoolExecutor源码分析(一)

1.线程池简介 1.1 线程池的概念: 线程池就是首先创建一些线程,它们的集合称为线程池.使用线程池可以很好地提高性能,线程池在系统启动时即创建大量空闲的线程,程序将一个任务传给线程池,线程池就会启动一条线程来执行这个任务,执行结束以后,该线程并不会死亡,而是再次返回线程池中成为空闲状态,等待执行下一个任务. 1.2 线程池的工作机制 在线程池的编程模式下,任务是提交给整个线程池,而不是直接提交给某个线程,线程池在拿到任务后,就在内部寻找是否有空闲的线程,如果有,则将任务交给某个空闲的线程. 一

Tomcat线程池,更符合大家想象的可扩展线程池

因由 说起线程池,大家可能受连接池的印象影响,天然的认为,它应该是一开始有core条线程,忙不过来了就扩展到max条线程,闲的时候又回落到core条线程,如果还有更高的高峰,就放进一个缓冲队列里缓冲一下. 有些整天只和SSH打交道的同学,可能现在还是这样认为的. 无情的现实就是,JDK只有两种典型的线程池,FixedPool 与 CachedPool: FixedPool固定线程数,忙不过来的全放到无限长的缓冲队列里. CachedPool,忙不过来时无限的增加临时线程,闲时回落,没有缓冲队列.