使用Executor管理线程

时间:2022-01-05 02:16:11

  上一篇博客(第一个并发程序:定义任务和驱动任务)中,我们使用Thread对象启动线程,而java.util.concurrent包的Executor执行器提供了更好的管理Thread对象的方法,从而简化并发编程。Executor与客户端直接执行任务不同,它就像一个中介,我们无须显式地管理线程的生命周期。

CachedThreadPool

  CachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程(CachedThreadPool在执行过程中通常会创建与所需数量相同的线程,然后在它回收旧线程时停止创建新线程):

package com;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class Main { public static void main(String[] args) { ExecutorService executor = Executors.newCachedThreadPool();
for(int i=0;i<3;i++){
executor.execute(new LiftOff());
}
executor.shutdown();
} }

输出:

线程编号0--倒计时3
线程编号2--倒计时3
线程编号1--倒计时3
线程编号1--倒计时2
线程编号1--倒计时1
线程编号1--倒计时0
线程编号2--倒计时2
线程编号2--倒计时1
线程编号0--倒计时2
线程编号2--倒计时0
线程编号0--倒计时1
线程编号0--倒计时0

  常见的的情况是,单个的Executor被用来创建和管理系统中的所有任务,对shuntdown()方法的调用可以防止新任务被提交给这个Executor,如果我们在shuntdown()后再次提交任务,程序会抛出“java.util.concurrent.RejectedExecutionException”异常。

FixedThreadPool

  除了CachedThreadPool,FixedThreadPool使用了有限的线程集来执行所提交的任务,它可以一次性预先完成线程分配。

ExecutorService executor = Executors.newFixedThreadPool(2);

SingleThreadExecutor

  SingleThreadExecutor就像是线程数量为1的FixedThreadPool。如果向SingleThreadExecutor提交了多个任务,那么这些任务将排队,所有的任务将使用相同的线程。

package com;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; public class Main { public static void main(String[] args) {
ExecutorService executor = Executors.newSingleThreadExecutor();
for(int i=0;i<3;i++){
executor.execute(new LiftOff());
}
executor.shutdown();
} }

输出:

线程编号0--倒计时3
线程编号0--倒计时2
线程编号0--倒计时1
线程编号0--倒计时0
线程编号1--倒计时3
线程编号1--倒计时2
线程编号1--倒计时1
线程编号1--倒计时0
线程编号2--倒计时3
线程编号2--倒计时2
线程编号2--倒计时1
线程编号2--倒计时0

  SingleThreadExecutor不需要在共享资源上处理同步,因为它可确保任意时刻只有唯一的任务在运行。

采用Executor的优势

  1.由于在任何线程池中,现有线程在可能的情况下,都会被自动复用。因此使用线程池比每次new Thread驱动任务的性能更加,它减少了对象创建、消亡的开销

  2.可有效控制最大并发线程数

  3.提供单线程控制功能