- Executor框架结构
①任务:需要实现的接口:Runnable和Callable。
②任务的执行:任务执行核心顶层接口Executor,继承自Executor的ExecutorService接口,Executor框架的两个关键类实现了了ExecutorService(ThreadPoolExecutor和ScheduledThreadPoolExecutor)。
③异步计算的结果:接口Future和实现Future接口的FutureTask类。
Executor框架的类与接口
Executor是框架的基础,是顶层接口,任务提交和任务执行分离。
ThreadPoolExecutor是线程池的核心实现类,用来执行提交的任务。
ScheduledThreadPoolExecutor实现类可以在给定的延迟后运行命令,或者定期执行命令。比Timer更灵活,功能更强大。
Future接口和实现Future接口的FutureTask类,代表异步计算的结果。
Runnable接口和Callable接口的实现类,都可以被ThreadPoolExecutor或ScheduledThreadPoolExecutor执行。
Runnable与Callable联系与区别
(1)Callable实现方法是call(),Runnable实现方法是run()
(2)Callable的任务执行后可以返回值,而Runnable的任务无返回值
(3)call方法可以抛出异常,run方法内部消化
(4)运行Callable任务可以拿到一个Future对象,表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。通过Future对象可以了解任务执行情况,可取消任务的执行,还可通过get阻塞方法获取执行结果。
// FutureTask实现了Runnable和future,使用FutureTask包装callable
FutureTask<String> task = new FutureTask<>(new Callable<String>(){
@Override
public String call() throws Exception {
Thread.sleep(10000);
return "Callable wrapper";
}
});
new Thread(task).start();
System.out.println(task.get()); //阻塞获取执行结果
// runnable转换为Callable处理,callable静态方法可以手动设置返回值,不设置返回null
Runnable task = new Runnable(){
@Override
public void run() {
System.out.println("runnable is running");
}
};
Callable<String> callable = Executors.callable(task, "return value");
ExecutorService myExecutor = Executors.newCachedThreadPool();
Future<String> future = myExecutor.submit(callable);
System.out.println(future.get());
//上述提到submit,顺便理下submit和execute的区别
①execute只能提交Runnable类型的任务,而submit既能提交Runnable类型任务也能提交Callable类型任务,submit执行runnable通过future获取结果都为空值。
②execute方法不关心返回值,submit方法有返回值Future。
③excute方法会抛出异常。sumbit方法不会抛出异常。除非你调用Future.get()。
Executor框架的主要成员
ThreadPoolExecutor:通常使用工厂类Executors来创建三种类型的ThreadPoolExecutor:SingleThreadExecutor、FixedThreadPool和CachedThreadPool。这三种ThreadPoolExecutor都是调用 ThreadPoolExecutor 构造函数进行创建,区别在于参数不同。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
}
FixedThreadPool的corePoolSize和maximumPoolSize都被设置为创建FixedThreadPool时指定的参数nThreads。当线程池中的线程数大于corePoolSize时,keepAliveTime为多余的空闲线程等待新任务的最长时间,超过这个时间后多余的线程将被终止。这里把keepAliveTime设置为0L,意味着多余的空闲线程会被立即终止。
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));
}
SingleThreadExecutor的corePoolSize和maximumPoolSize被设置为1。其他参数与FixedThreadPool相同。SingleThreadExecutor使用无界队列LinkedBlockingQueue作为线程池的工作队列(队列的容量为Integer.MAX_VALUE)。SingleThreadExecutor使用无界队列作为工作队列,对线程池带来的影响与FixedThreadPool相同(OOM)。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
}
CachedThreadPool的corePoolSize被设置为0,即corePool为空;maximumPoolSize被设置为Integer.MAX_VALUE,即maximumPool是无界的。这里把keepAliveTime设置为60L,意味着CachedThreadPool中的空闲线程等待新任务的最长时间为60秒,空闲线程超过60秒后将会被终止。CachedThreadPool使用没有容量的SynchronousQueue作为线程池的工作队列,但CachedThreadPool的maximumPool是无界的。这意味着,如果主线程提交任务的速度高于maximumPool中线程处理任务的速度时,CachedThreadPool会不断创建新线程。极端情况下,CachedThreadPool会因为创建过多线程而耗尽CPU和内存资源。
ScheduledThreadPoolExecutor实现了可调度的线程池功能:
①指定延时后执行任务
②周期性重复执行任务
ScheduledThreadPoolExecutor extends ThreadPoolExecutor implements ScheduledExecutorService
ScheduledThreadPoolExecutor继承自ThreadPoolExecutor,ScheduledThreadPoolExecutor的功能与Timer类似,但它的功能更强大、更灵活。Timer对应的是单个后台线程,而它可以在构造函数中指定多个对应的后台线程数。使用无界队列DelayQueue存储ScheduledFutureTask,所以ThreadPoolExecutor的maximumPoolSize在ScheduledThreadPoolExecutor中没有什么意义。
ScheduledFutureTask主要包含3个成员变量。
long型成员变量time,表示这个任务将要被执行的具体时间。
long型成员变量sequenceNumber,表示这个任务被添加到ScheduledThreadPoolExecutor中的序号。
long型成员变量period,表示任务执行的间隔周期。
DelayQueue底层实现通过优先级队列PriorityQueue,这个PriorityQueue会对队列中的ScheduledFutureTask进行排序。排序规则:time由小到大(最先到期排前),time相同按sequenceNumber由小到大(先提交排前)//可调度的执行者服务接口
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);
}
schedule:用于单次调度执行任务,不做解释。
scheduleAtFixedRate:该方法在initialDelay时长后第一次执行任务,以后每隔period时长,再次执行任务。注意,period是从任务开始执行算起的。开始执行任务后,定时器每隔period时长检查该任务是否完成,如果完成则再次启动任务,否则等该任务结束后才再次启动任务。scheduleWithFixDelay:该方法在initialDelay时长后第一次执行任务,以后每当任务执行完成后,等待delay时长,再次执行 任务。
Future接口
Future接口提供方法来检测任务是否被执行完,等待任务执行完获得结果,也可以设置任务执行的超时时间,这个设置超时 的方法就是实现Java程序执行超时的关键。
Future接口是一个泛型接口,严格的格式应该是Future<V>,其中V代表了Future执行的任务返回值的类型。 Future接口的 方法介绍如下:
boolean cancel (boolean mayInterruptIfRunning) 取消任务的执行。参数指定是否立即中断任务执行,或者等任务结束。
boolean isCancelled () 任务是否已经取消,任务正常完成前将其取消,则返回 true。
boolean isDone () 任务是否已经完成。需要注意的是如果任务正常终止、异常或取消,都将返回true。
V get () throws InterruptedException, ExecutionException 等待任务执行结束,然后获得V类型的结果。 InterruptedException 线程被中断异常, ExecutionException任务执行异常,如果任务被取消,还会抛出CancellationException
V get (long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException 同上面的get功能一样,多了设置超时时间。参数timeout指定超时时间,uint指定时间的单位,在枚举类TimeUnit中有相关的定义。如果计算超时,将抛出TimeoutException。FutureTask简介
Future接口和实现Future接口的FutureTask类,代表异步计算的结果,FutureTask除了实现Future接口外,还实现了Runnable接口。因此,FutureTask可以交给Executor执行,也可以由调用线程直接执行(FutureTask.run())。根据FutureTask.run()方法被执行的时机,FutureTask可以处于下面3种状态,FutureTask的状态迁移示意图。FutureTask的get和cancel的执行示意图
/**
* Possible state transitions:
* NEW -> COMPLETING -> NORMAL
* NEW -> COMPLETING -> EXCEPTIONAL
* NEW -> CANCELLED
* NEW -> INTERRUPTING -> INTERRUPTED
*/
private volatile int state;
// 初始状态,还没有执行的,这个是在构造方法中进行赋值的
private static final int NEW = 0;
// 任务已经执行完成或者执行任务的时候发生异常,但是任务执行结果或者异常原因还没有保存到outcome字段(outcome字段用来保存任务执行结果,如果发生异常,则用来保存异常原因)的时候,状态会从NEW变更到COMPLETING。但是这个状态会时间会比较短,属于中间状态
private static final int COMPLETING = 1;
//任务正常执行完的最终状态
private static final int NORMAL = 2;
// 任务发生异常时的最终状态
private static final int EXCEPTIONAL = 3;
// 任务取消时的状态,任务取消当并不中断,即只调用了cancel(false)方法
private static final int CANCELLED = 4;
// 用户调用了cancel(true)方法取消任务,状态会从NEW转化为INTERRUPTING,一个中间态,终态是INTERRUPTED。
private static final int INTERRUPTING = 5;
// 调用interrupt()中断任务,中断任务的最终状态
private static final int INTERRUPTED = 6;
java并发编程之Executor框架
最新推荐文章于 2024-08-03 15:03:17 发布