今天看了一下java并发包中的API,这里做一个总结。
首先我们先看一下,java线程池相关的类以及他们的关系uml图
从类图和源码中可以了解到,Executors类是提供线程池创建的类,而实现Executo接口系列的类则是提供线程池所有用的行为。例如execute、submit、shutDown等
Executors类中提供四种创建线程池的静态方法。
创建线程池的几种方式
创建缓存线程池
- 创建可缓存的线程池,如果没有可用的线程,会创建一个新的,并销毁超过60s没有重用的线程
public static void newCachedThreadPool(){
MyRunnable myRunnable = new MyRunnable();
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i = 0; i < 5; i++) {
executorService.execute(myRunnable);
}
executorService.shutdown();
}
创建固定数量的线程池
- 创建固定线程数的线程池
public static void newFixedThreadPool(){
MyRunnable myRunnable = new MyRunnable();
ExecutorService executorService = Executors.newFixedThreadPool(5);
for (int i = 0; i < 5; i++) {
executorService.execute(myRunnable);
}
executorService.shutdown();
}
创建单一线程的线程池
- 创建一个单线程化的Executor。
public static void newSingleThreadExecutor(){
MyRunnable myRunnable = new MyRunnable();
ExecutorService executorService = Executors.newSingleThreadExecutor();
for (int i = 0; i < 5; i++) {
executorService.execute(myRunnable);
}
executorService.shutdown();
}
创建具有周期性的线程池
public static void newSchduleThreadExecutor(){
MyRunnable myRunnable = new MyRunnable();
ScheduledExecutorService executorService = Executors.newScheduledThreadPool(5);
for (int i = 0; i < 5; i++) {
executorService.execute(myRunnable);
}
executorService.shutdown();
}
对源码进行的一番分析
通过查看Executors的源码可以了解到其中newCachedThreadPool()和newFixedThreadPool(int nThreads)创建多线程的方法其实是交给ThreadPoolExecutor来执行的。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
ThreadPoolExecutor的构造方法有以下参数说明:
corePoolSize 核心线程数
maximumPoolSize 允许的最大线程数
keepAliveTime 单个线程存或时间
TimeUnit 持续时间的单位
BlockingQueue 任务执行前保持任务的队列
我们可以根据ThreadPoolExecutor提供的构造方法来自定义线程池
//创建等待队列
BlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<Runnable>(10);
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 10, 60L, TimeUnit.SECONDS, blockingQueue);
for (int i = 0; i <10 ; i++) {
threadPoolExecutor.submit(new MyCallable<String>());
}
threadPoolExecutor.shutdown();
ExecutorService的行为方法
通过Executors创建方式可以查看到,newCachedThreadPool和newFixedThreadPool线程池的创建返回对象是ExecutorService,这是一个提供线程池操作的接口。
它的execute()和submit方法值得我们了解一下
从线程池的继承结构来看,它们都继承Executor接口,该接口只提供一个方法
void execute(Runnable command);
因此所有创建的线程池都会有execute的方法实现,ExecutorService还提供了不同的submit方法和终止线程的shutdown方法
//带Future返回值的submit方法。
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);
//结束多线程的执行
void shutdown();
我们看到ExecutorService提供的submit中传入的参数有两类,一类是Runnable,另一类是Callable。Runnable大家都很熟悉了,是创建多线程提供的接口方法。我们可以通过实现Runnable接口来实现一个多线程要执行的run方法。但是这个run方法没有返回值,而Calleable接口与Runnable类似,唯一不同的就是它有返回值
@FunctionalInterface
public interface Callable<V> {
V call() throws Exception;
}
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
Callable接口
从这里我们就看出ExecutorService的submit的区别了,
一个传入Callable参数的submit方法可以有返回值,
传入Runnable参数的submit方法没有返回值。
我们可以通过例子看下Callable的用法
public static void callableSubmitTest() throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
List<Future<String>> list = new ArrayList<Future<String>>();
for (int i = 0; i <10 ; i++) {
Future<String> future = executorService.submit(new MyCallable<String>());
list.add(future);
}
for (int i = 0; i < list.size(); i++){
Future<String> future = list.get(i);
System.out.println("future.get() = " + future.get() + " is canceled :" + future.isDone());
}
executorService.shutdown();
}
static class MyCallable<String> implements Callable<String>{
public String call() throws Exception {
System.out.println(Thread.currentThread().getName() + " 线程名...");
return (String) Thread.currentThread().getName();
}
}
Future
ExecutorService的submit都返回了Future对象,而这个对象是做什么用的呢?
Future也是一个接口类,这里面定义了多线程任务的完成状态。
例如isCanceled()、isDone()等等这些方法,用于判断多线程任务的执行状态。
通过Future的get()方法获取Callable返回的结果。
//在任务完成之前结束,返回true
boolean isCancelled();
//在任务完成后,返回true
boolean isDone();
//获取结果值
V get();
还有一个ScheduleExecutorService的方法没有进行介绍,下一次再与大家分享!
参考博客:
http://wiki.jikexueyuan.com/project/java-concurrency/executor.html
代码例子:
https://github.com/hpulzl/lzl_workspace/tree/master/thread_demo