Java的线程既是工作单元,也是执行机制。从JDK5开始,把工作单元与执行机制分离开来。工作单元包括Runnable
和Callable
,而执行机制由Executor
框架提供。
Executor 框架简介
在HotSpot VM
的线程模型中,Java线程被一对一映射为本地操作系统线程。Java线程启动时会创建一个本地操作系统线程;当该Java线程终止时,这个操作系统线程也被收回。操作系统会调度所有线程并将他们分配给可用的CPU。如图
Executor 框架结构
主要由3大部分组成:
- 任务:包括被执行任务需要实现的接口:
Runnable
接口和Callable
接口 - 任务的执行:包括任务执行机制的核心接口
Executor
,以及继承自它的ExecutorService
接口。有两个关键类实现了ExecutorService
接口(ThreadPoolExecutor
和ScheduledThreadPoolExecutor
)。 - 异步计算的结果:包括接口
Future
和实现它的FutureTask
类
Executor框架的成员
ThreadPoolExecutor:通常使用工具类
Executors
来创建。Executors
可以创建3种类型的ThreadPoolExecutor
:SingleThreadExecutor:用于需要保证顺序地执行每个任务,并且在任意时间点不会有多个线程是活动的应用场景。下面是创建单个线程的API
12public static ExecutorService newSingleThreadExecutor();public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory)FixedThreadPool:用于为了满足资源管理的需求,而需要限制当前线程数量的应用场景,它适用于负载比较重的服务器。下面是创建使用固定线程数的
FixedThreadPool
的API12public static ExecutorService newFixedThreadPool(int nThreads);public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory);CachedThreadPool:它是无界大小的线程池,用于执行很多短期异步小任务的小程序,或者是负载比较轻的服务器。下面是创建一个根据需要创建新线程的API
12public static ExecutorService newCachedThreadPool();public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory);
ScheduledThreadPoolExecutor:通常使用工具类
Executors
来创建。Executors
可以创建2种类型的ScheduledThreadPoolExecutor
:ScheduledThreadPoolExecutor:包含若干个线程的ScheduledThreadPoolExecutor,适用于需要多个后台线程执行周期任务,同时为了满足资源管理的需求而需要限制后台线程的数量的场景。下面是创建的API:
123public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize);public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory);SingleThreadScheduledExecutor:只包含一个线程的ScheduledThreadPoolExecutor,适用于需要单个线程执行周期任务,同时需要保证顺序地执行各个任务的场景。下面是创建的API:
12public static ScheduledExecutorService newSingleThreadScheduledExecutor();public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory);
Future接口
Future
接口和实现Future
接口的FutureTask
类用来表示异步计算的结果。当我们把Runnable
接口或Callable
接口的实现类提交(submit)给ThreadPoolExecutor
或ScheduledThreadPoolExecutor
时,ThreadPoolExecutor
或ScheduledThreadPoolExecutor
会向我们返回一个FutureTask
对象。下面是对应API:123public <T> Future<T> submit(Callable<T> task)public <T> Future<T> submit(Runnable task, T result)public Future<?> submit(Runnable task)Runnable接口和Callable接口
这两个接口的实现类都可以被ThreadPoolExecutor
或ScheduledThreadPoolExecutor
执行,最后一个方法没有返回值,其他均可以通过得到的FutureTask
对象的get方法获取执行后结果。12345678910111213141516171819202122232425262728293031public class ExecutorTest {public static void main(String[] args) throws ExecutionException, InterruptedException {ExecutorService executor = Executors.newFixedThreadPool(5);//submit(Runnable task)Future<String> f1 = executor.submit(new Runnable(){@Overridepublic void run() {System.out.println(1);}},"result");System.out.println(f1.get());//submit(Runnable task,T result)Future f2 = executor.submit(new Runnable(){@Overridepublic void run() {System.out.println(2);}});System.out.println(f2.get());//submit(Callable<T> task)Future<String> f3 = executor.submit(new Callable<String>() {@Overridepublic String call() throws Exception {System.out.println(3);return "result";}});System.out.println(f3.get());}}
执行结果
除了自己实现Callable
接口外,Executors
可以把一个Runnable
包装成一个Callable
,下面是对应的API
此时将这种转换过的对象交给ThreadPoolExecutor
或ScheduledThreadPoolExecutor
执行时,第一个种转换方法不会有返回值。
执行结果