Executor 、future学习(一)

Executor 

executor包括三个部分

1.任务,即工作单元,包括被执行的任务需要实现的接口:runnable货callabe接口

2.任务的执行,把任务分配给多个线程执行的机制,包括Executor接口及继承自Executor接口的ExecutorService接口

3.异步计算的结果,包括Future及实现了Future接口的FutureTask类

Executor

一个接口,定义了一个接受runnable对象的方法execute(Runnable command),接受一个runnable实例,用来执行一个任务,任务为一个实现了Runnable接口的类,在Executor中,可以不显示的创建线程executor.execute(new MyRunnable)来异步执行

ExecutorService

是一个比Executor更广泛的子类接口,继承Executor接口,提供生命周期管理方法:

shutDown():关闭当前service,释放Executor的所有资源,触发的动作是取消消息队列中任务的执行,不再接受新的任务提交,同时把已经提交到队列的任务执行完成

shutDownNow:它将会把尚未执行的任务不再执行,正在执行的任务,通过“线程中断”(thread.interrupt),如果线程无法响应“中断”,那么将不会通过此方式被立即结束,该方法具有返回值,返回等待执行的任务列表List<Runnable>

isShutDown:程序是否关闭

isTerminated:是否已经结束,如果关闭后,所有的任务都执行完成,返回true,其他情况均为false

awaitTermination(timeout):等待一段之间直到“任务全部结束”,如果超时就返回false

Future submit(callable/runnale):向Executor提交任务,并返回一个结果未定的Future

List<Future> invokeAll(Collection<Callable>):同步的方法,执行所有的任务列表,当所有任务都执行完成后,返回Future列表

T invokeAny(Collection<Callable>): 任务集合中,任何一个任务完成就返回

ScheduledExecutorService

设计为了支持时间可控的任务执行:固定延时执行,周期延时执行,核心方法:

schedule(Callable<V> callable, long delay, TimeUnit unit)

schedule(Runnable command, long delay, TimeUnit unit)

这两个方法是延时执行,只是传入的参数不同

scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)

周期执行

scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)

当前一个任务执行完成之后,延时delay,再开始执行第二个任务

 

框架示意图

ScheduledThreadPool

创建一个大小无线的线程池,支持定时及周期性执行任务的需求

创建线程池要用到ThreadPoolExecutor

 

自定义线程池:ThreadPoolExecutor

 

corePoolSize:线程池中所保存的核心线程数,包括空闲线程

maximumPoolSize:池中允许最大的线程数

keepAliveTime:线程池中空闲线程能保存的最长时间

unit:持续时间的单位

workQueue:任务执行前保存任务的队列,仅保存由execute方法提交的runnable任务,有四种阻塞队列

(a)ArrayBlockingQueue

(b)LinkedBlockingQueue

(c)SynchronousQueue

(d)PriorityBlockingQueue

newFixedThreadPool使用了LinkedBlockingQueue,newCachedThreadPool使用了SynchronousQueue

threadFactory:新线程使用ThreadFactory创建,如果没有指定,则使用Executors.defaultThreadFactory默认工厂

handler:饱和策略的句柄,当线程池包满了,任务无法得到处理,需要使用饱和策略来处理无法完成的任务,有四种策略

(a)AbortPolicy:默认策略,直接抛出异常

(b)CallerRunPolicy:调用者所在线程来运行任务

(c)DiscardOldestPolicy:丢弃队列中最老的任务,并执行当前任务

(d)DiscardPolicy:不处理,直接丢弃当前任务

可以自定义饱和策略,需要实现RejectExecutionHandler接口

 

向线程提交任务有两种方法:execute和submit

execute用于提交没有返回值的任务,所以无法判断任务是否被执行过

 

 

submit用于提交需要返回值的对象,返回一个future对象,可以通过future对象判断任务是否被线程执行,future.get()获取返回的值,get方法会阻塞当前线程直道future对象被返回,也可以使用get(long timeout,TimeUnit unit)来实现由等待时间的获取返回值,如果超市仍没有返回值,那么立刻返回,这时任务可能仍没有执行

关闭线程池

遍历线程池中的线程,逐个调用线程的interrupt来中断线程,不响应中断的线程可能无法停止

(a)shutDown:把线程的状态置为shutdown,然后中断所有没有正在执行任务的线程,已经在执行任务的线程继续执行到任务完成

(b)shutDownNow:把当前线程池状态置为stop,尝试停止所有的正在执行或暂停的线程,并返回等待执行任务的列表

调用之后,调用isShutDown返回true,当所有任务都关闭后,调用isTerminaed返回true

 

当通过execute方法将一个runnable任务添加到线程池中,处理顺序:

1.如果线程池中的数量小于corePoolSize,即使线程池中有空闲的线程,也会创建一个新线程来执行新添加的任务

2.如果线程池中的数量大于等于corePoolSize,但是workQueue缓冲队列未满,则将新添加的任务放到workQueue中,线程池中有线程空闲出来后,依次将workQueue中的任务交给空闲的线程执行

3.如果线程池中的数量大于等于corePoolSize,而且workQueue缓冲队列也满了,但线程池中的数量小于maximunPoolSize,则会创建新的线程来处理被添加的任务

4.如果线程池中的数量等于maximumuPoolSize,使用RejectedExecutionHandler处理溢出线程

当有新的任务处理,先看线程池中的线程数量是否大于corePoolSize,再看缓冲队列workQueue是否满了,最后看线程池中的数量是否大于maximumuPoolSize

当线程池中的线程数量大于corePoolSize,如果里面有线程的空闲时间超过了keepAliveTime,就将其移除线程池。

使用核心线程池+阻塞队列+线程池的设计思路的优点

创建新的线程需要获取全局锁,为了避免频繁的获取全局锁,使用一个阻塞队列来存储任务,如果核心线程池中的线程执行任务的周期短,那么执行完毕后立即从阻塞队列中获取任务,避免了重新创建线程,使线程的重复利用率提高,如果核心线程池中的执行周期长,使得阻塞队列满了还不断的提交任务,这时再创建线程,使用一个核心线程池,一个线程池,是因为核心线程池容量不能太大,不然阻塞队列的缓存作用就降低了,但是如果线程池的数量太小,就限制了并发的线程数,降低了CPU的利用率

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Spring Boot中,可以使用`ThreadPoolTaskExecutor`类来初始化一个Executor。下面是一个简单的示例: ```java import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; @Configuration public class ExecutorConfig { @Bean public ThreadPoolTaskExecutor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(10); //设置核心线程数 executor.setMaxPoolSize(20); //设置最大线程数 executor.setQueueCapacity(100); //设置队列容量 executor.setThreadNamePrefix("MyExecutor-"); //设置线程名称前缀 executor.initialize(); //初始化Executor return executor; } } ``` 在上面的示例中,我们定义了一个`taskExecutor()`方法,用于初始化`ThreadPoolTaskExecutor`对象。我们可以通过调用`setCorePoolSize()`、`setMaxPoolSize()`和`setQueueCapacity()`方法来设置线程池的一些属性。最后,调用`initialize()`方法来完成Executor的初始化。 注意,我们需要将`@Configuration`注解添加到我们的配置类上,以便Spring Boot能够自动扫描并加载该类。另外,我们还需要将初始化后的Executor注入到需要使用的类中,例如: ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Component; @Component public class MyService { @Autowired private ThreadPoolTaskExecutor taskExecutor; public void doSomething() { taskExecutor.execute(() -> { //执行具体的任务 }); } } ``` 在上面的示例中,我们使用`@Autowired`注解将初始化后的Executor注入到`MyService`类中。然后,我们可以在`doSomething()`方法中使用`taskExecutor`来执行具体的任务。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值