详解Java中的线程池
作者:辣鸡小篮子 发布时间:2023-11-10 16:33:27
1.简介
使用线程池可以避免线程的频繁创建以及销毁。
JAVA中提供的用于实现线程池的API:
Executor、ExecutorService、AbstractExecutorService、ThreadPoolExecutor、ForkJoinPool都位于java.util.concurrent包下。
*ThreadPoolExecutor、ForkJoinPool为线程池的实现类。
2.Executor
public interface Executor {
/**
* 向线程池提交一个任务,交由线程池去执行
*/
void execute(Runnable command);
}
*该接口声明了execute(Runnable command)方法,负责向线程池中提交一个任务。
3.ExecutorService接口
public interface ExecutorService extends Executor {
/**
* 关闭线程池(等待队列中的任务被执行完毕)
*/
void shutdown();
/**
* 立刻关闭线程池(不执行队列中的任务,并尝试中断当前执行的任务)
*/
List<Runnable> shutdownNow();
/**
* 判断线程池是否处于shutdown状态.
*/
boolean isShutdown();
/**
* 判断线程池是否处于terminated状态.
*/
boolean isTerminated();
/**
* 若在指定时间内线程池处于terminated状态则立即返回true,否则超过时间后仍未为terminated状态则返回false.
*/
boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;
/**
* 向线程池提交一个任务并返回包含指定类型的Future(根据Callable的泛型)
*/
<T> Future<T> submit(Callable<T> task);
/**
* 向线程池提交一个任务并指定任务执行结果的类型,返回包含指定类型的Future.
*/
<T> Future<T> submit(Runnable task, T result);
/**
* 向线程池提交一个任务并返回未知类型的Future.
*/
Future<?> submit(Runnable task);
/**
* 向线程池提交多个任务并返回指定类型的Future列表.
*/
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException;
/**
* 向线程池提交多个任务并返回指定类型的Future列表,如果在指定时间内没有执行完毕则直接返回.
*/
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException;
/**
* 向线程池提交多个任务,当任意一个任务执行完毕后返回指定类型的Future.
*/
<T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException;
/**
* 向线程池提交多个任务,在指定时间内,当任意一个任务执行完毕后返回指定类型的Future,若超时则抛出异常.
*/
<T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}
public interface Future<V> {
/**
* 中断任务的执行
*/
boolean cancel(boolean mayInterruptIfRunning);
/**
* 判断任务是否中断成功
*/
boolean isCancelled();
/**
* 判断任务是否执行完成
*/
boolean isDone();
/**
* 获取任务的执行结果直到任务执行完毕(阻塞线程)
*/
V get() throws InterruptedException, ExecutionException;
/**
* 获取任务的执行结果,若在指定时间内任务仍然没有执行完毕则抛出TimeoutException
*/
V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}
*execute()方法不能获取任务的执行结果,而submit()方法能够根据返回的Future实例获取任务的执行结果。
4.ThreadPoolExecutor
corePoolSize:线程池中核心线程的数量。
maximumPoolSize:线程池中最大线程数。
keepAliveTime:线程的空闲时间。
unit:修饰线程空闲时间的单位。
workQueue:任务队列。
threadFactory:线程工厂,用于创建线程。
handler:当队列已满且当前线程数已达到所允许的最大值时的处理策略。
*线程池中的线程包括核心线程以及普通线程,核心线程一旦创建后直到线程池被关闭前都就不会被销毁,而普通线程会因为到达空闲时间而被销毁。
构造方法:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
BlockingQueue的类型
BlockingQueue提供了ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue等实现类。
1.ArrayBlockingQueue:使用顺序表的结构进行存储,在使用时需要指定其长度,支持公平锁/非公平锁进行操作。
2.LinkedBlockingQueue:使用链表的结构进行存储,在使用时不需要指定其长度,队列的最大长度为Integer.MAX_VALUE。
3.SynchronousQueue:一个不存储元素的队列,每一个put操作必须等待take操作,否则不能添加元素,支持公平锁和非公平锁。
*这些实现类在进行入队和出队操作时都会进行加锁,以保证在多线程并发访问时数据的安全性。
队列已满且线程数已达到所允许的最大值时的处理策略
RejectedExecutionHandler提供了AbortPolicy、DiscardPolicy、DiscardOlderstPolicy、CallerRunsPolicy四个策略,这四个策略都是ThreadPoolExecutor的静态内部类。
1.AbortPolicy:放弃任务并抛出RejectedExecutionException异常。
2.DiscardPolicy:放弃任务但不抛出异常。
3.DiscardOlderstPolicy: 放弃队头中的任务,然后重新尝试执行新任务。
4.CallerRunsPolicy: 由调用线程来处理该任务。
线程池的状态
private static final int RUNNING = -1;
private static final int SHUTDOWN = 0;
private static final int STOP = 1;
private static final int TIDYING = 2;
private static final int TERMINATED = 3;
1.RUNING:线程池处于运行状态,此时可以接受新的任务请求,并且执行队列中的任务。
2.SHUTDOWN:线程池处于关闭状态,此时不接受新的任务请求,但会继续执行队列中的任务。
3.STOP:线程池处于禁用状态,此时不接受新的任务请求,并且不会执行队列中的任务。
4.TIDYING:线程池处于整理状态,此时没有正在执行的任务。
5.TERMINATED :线程池处于终止状态。
线程池状态的变化过程
1.当线程池创建后处于RUNNING状态。
2.1 若此时调用了shutdown()方法,那么线程池将处于SHUTDOWN状态,不接受新的任务请求,但会继续执行队列中的任务,当队列中的任务为空且没有正在执行的任务时,线程池的状态为TIDYING。
2.2 若此时调用了shutdownNow()方法,那么线程池将处于STOP状态,不接受新的任务请求并且不执行队列中的任务,此时线程池的状态为TIDYING。
3.当线程池的状态为TIDYING时,当terminated()方法处理完毕后,线程池的状态为TRRMINATED。
任务的执行流程
1.当调用了execute()或者submit()方法向线程池提交一个任务后,首先判断当前线程池中的线程个数是否大于核心线程数。
2.如果当前线程池的线程个数小于核心线程数,则创建一个核心线程来处理任务。
3.如果当前线程池的线程个数大于核心线程数,则将任务放入到队列中,如果放入队列成功,那么该任务将等待被空闲的线程处理,如果放入队列失败(队满),则判断当前线程池中的线程个数是否达到所允许的最大值,若未达到则创建一个普通线程去处理任务,否则根据预定义的处理策略去进行处理。
5.Executors工具类
JAVA中提供了Executors工具类,用于直接创建Executor。
CacheThreadPool
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());
}
CacheThreadPool创建的都是普通线程(其核心线程数为0)、线程池的最大线程数为Integer.MAX_VALUE、线程的空闲时间为60秒,此方式适合大量耗时短的任务、不适合大量耗时长的任务。
*由于创建的都是普通线程,且空闲时间为60秒,则仍有可能会频繁的创建线程。
FixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
}
FixedThreadPool创建的都是核心线程,其线程个数由入参决定,线程不会因为空闲时间而被销毁,适合预知任务数量的业务。
SingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,new LinkedBlockingQueue<Runnable>()));
}
SingleThreadExecutor使用一个核心线程来处理任务。
ScheduledThreadPool
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
*ScheduledThreadPool支持定时执行任务以及固定间隔执行任务。
SingleThreadScheduledExecutor
public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
return new DelegatedScheduledExecutorService(new ScheduledThreadPoolExecutor(1));
}
*SingleThreadScheduledExecutor支持一个线程的定时执行任务以及固定间隔执行任务。
public interface ScheduledExecutorService extends ExecutorService {
/**
* 在指定的延迟时间到达后执行任务一次
*/
public ScheduledFuture<?> schedule(Runnable command,long delay, TimeUnit unit);
/**
* 在指定的延迟时间到达后执行任务一次
*/
public <V> ScheduledFuture<V> schedule(Callable<V> callable,long delay, TimeUnit unit);
/**
* 在指定的初始化延迟时间到达后执行任务一次,往后每隔period时间执行任务一次.
*/
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit);
/**
* 在指定的初始化延迟时间到达后执行任务一次,往后每次任务执行完毕后相隔delay时间执行任务一次.
*/
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit);
}
WorkStealingPool
public static ExecutorService newWorkStealingPool(int parallelism) {
return new ForkJoinPool(parallelism,ForkJoinPool.defaultForkJoinWorkerThreadFactory,null, true);
}
WorkStealingPool创建一个并行级别的线程池,同一时刻最多只能有指定个数个线程正在执行任务,创建时直接指定同一时刻最多能允许的并行执行的线程个数即可,如果不传则使用CPU的核数。
newWorkStealingPool方法内部返回一个ForkJoinPool实例,ForkJoinPool是JAVA7新提供的线程池,同样继承AbstactExecutorService。
*作用类似于Semaphore。
以上所述是小编给大家介绍的Java中的线程池详解整合,希望对大家有所帮助。
来源:https://www.cnblogs.com/funyoung/p/10530986.html
猜你喜欢
- FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化
- 1.登录腾讯云点击登录选择浏览器登录。输入用户名 按回车键 然后输入 密码。2.安装java环境直接命令:yum -y install ja
- 起源flutter作为一个跨平台的框架,在绘制上体现出了它跨平台的良好性能.那么,它是如何从runApp()后 绘制上屏的呢?本文将与你一起
- 一、方法这里我们用两种方法来实现跑马灯效果,虽然实质上是一种实质就是:1、TextView调出跑马灯效果2、TextView获取焦点&nbs
- 功能函数// 图像旋转void Rotate(const cv::Mat &srcImage, cv::Mat &dstIm
- Mybatis 复杂对象resultMap数据对象含有普通属性,一对一对象,一对多对象(2种情况:单一主键和复合主键)下面是resultMa
- 第1部分 ArrayList介绍ArrayList简介ArrayList 是一个数组队列,相当于 动态数组。与Java中的数组相比,它的容量
- 为什么要使用路由在之前我们的代码中,页面跳转使用的代码如下所示:Navigator.of(context).push( Mate
- package cn.response;import java.awt.Color;import java.awt.Font;import
- Java BufferWriter写文件之后文件是空的或者数据不全在编程的过程中,读写文件是非常常见的操作,在这里我问介绍一下最近我遇到的集
- 1.<constant name="struts.i18n.encoding" value="UTF-8
- 自动登录是我们在软件开发时一个非常常见的功能,例如我们登录 QQ 邮箱:很多网站我们在登录的时候都会看到类似的选项,毕竟总让用户输入用户名密
- Java NIO(New IO)是Java 1.4版本中引入的一套全新的IO处理机制,与之前的传统IO相比,NIO具有更高的可扩展性和灵活性
- 前言本文给你提供在Spring Boot 应用程序中编写好的单元测试的机制,并且深入技术细节。我们将带你学习如何以可测试的方式创建Sprin
- Handler是什么?Handler 是一个可以实现多线程间切换的类,通过 Handler 可以轻松地将一个任务切换到 Handler 所在
- 一.关于使用Mybatisplus自带的selectById和insert方法时的一些问题1.selectById的问题(1).表的主键列名
- 一、实现方式@ConfigurationProperties 注解(最好加上前缀prefix=“person”,标明是和配置文件中哪个开头的
- springboot 多个filter的执行顺序以及配置当项目中有多个filter时,为了便于管理,可以创建一个配置文件,对所有的filte
- 1.短信平台购买次数地址https://market.aliyun.com/products/57000002/cmapi00046920.
- 1、说明isInterrupted()可以判断当前线程是否被中断,仅仅是对interrupt()标识的一个判断,并不会影响标识发生任何改变(