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
public static ExecutorService newSingleThreadExecutor();public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory)
- FixedThreadPool:用于为了满足资源管理的需求,而需要限制当前线程数量的应用场景,它适用于负载比较重的服务器。下面是创建使用固定线程数的
FixedThreadPool
的API
public static ExecutorService newFixedThreadPool(int nThreads);public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory);
- CachedThreadPool:它是无界大小的线程池,用于执行很多短期异步小任务的小程序,或者是负载比较轻的服务器。下面是创建一个根据需要创建新线程的API
public static ExecutorService newCachedThreadPool();public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory);
- ScheduledThreadPoolExecutor:通常使用工具类
Executors
来创建。Executors
可以创建2种类型的ScheduledThreadPoolExecutor
:- ScheduledThreadPoolExecutor:包含若干个线程的ScheduledThreadPoolExecutor,适用于需要多个后台线程执行周期任务,同时为了满足资源管理的需求而需要限制后台线程的数量的场景。下面是创建的API:
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize);public static ScheduledExecutorService newScheduledThreadPool( int corePoolSize, ThreadFactory threadFactory);
- SingleThreadScheduledExecutor:只包含一个线程的ScheduledThreadPoolExecutor,适用于需要单个线程执行周期任务,同时需要保证顺序地执行各个任务的场景。下面是创建的API:
public static ScheduledExecutorService newSingleThreadScheduledExecutor();public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory);
- Future接口
Future
接口和实现Future
接口的FutureTask
类用来表示异步计算的结果。当我们把Runnable
接口或Callable
接口的实现类提交(submit)给ThreadPoolExecutor
或ScheduledThreadPoolExecutor
时,ThreadPoolExecutor
或ScheduledThreadPoolExecutor
会向我们返回一个FutureTask
对象。下面是对应API:
publicFuture submit(Callable task)public Future submit(Runnable task, T result)public Future submit(Runnable task)
- Runnable接口和Callable接口 这两个接口的实现类都可以被
ThreadPoolExecutor
或ScheduledThreadPoolExecutor
执行,最后一个方法没有返回值,其他均可以通过得到的FutureTask
对象的get方法获取执行后结果。
public class ExecutorTest { public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService executor = Executors.newFixedThreadPool(5); //submit(Runnable task) Futuref1 = executor.submit(new Runnable(){ @Override public void run() { System.out.println(1); } },"result"); System.out.println(f1.get()); //submit(Runnable task,T result) Future f2 = executor.submit(new Runnable(){ @Override public void run() { System.out.println(2); } }); System.out.println(f2.get()); //submit(Callable task) Future f3 = executor.submit(new Callable () { @Override public String call() throws Exception { System.out.println(3); return "result"; } }); System.out.println(f3.get()); executor.shutdown(); }}
执行结果
1result2null3result
除了自己实现Callable
接口外,Executors
可以把一个Runnable
包装成一个Callable
,下面是对应的API
public static Callable
此时将这种转换过的对象交给ThreadPoolExecutor
或ScheduledThreadPoolExecutor
执行时,第一个种转换方法不会有返回值。
Callable c1 = Executors.callable(new Runnable() { @Override public void run() { System.out.println(4); } }); Callable c2 = Executors.callable(new Runnable() { @Override public void run() { System.out.println(5); } },"result2"); Future f4 = executor.submit(c1); System.out.println(f4.get()); Future f5 = executor.submit(c2); System.out.println(f5.get());
执行结果
4null5result2