首先看ThreadPoolExecutor的继承关系:
其中AbstractExecutorService 又实现了ExecutorService接口。然而ExecutorService又继承了Executor接口。
Executor接口里面只有一个回调方法execute(Runnable command);
需要注意的是,command是可以执行在 被调用线程里的 ,例如下面(虽然大部分情况下不会这么做)
class DirectExecutor implements Executor {
public void execute(Runnable r) {
r.run();
}
}}
再看ExecutorService,通过阅读官方的说明文档我们可以知道,接口ExecutorService,给出一系列方法。例如shutdown,可以实时关闭Excutor执行等。另外还可以通过Future类来跟随判断当前执行任务的状态。Future通过ExcutorService里面的submit方法来返回得到。submit用来提交执行的新任务。Callable和Runable的区别在于。Callable 是一个带有返回数据返回方法的接口。而Runable
是一个不带有返回数据返回方法的接口
public interface Runnable {
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}
public interface Runnable {
public abstract void run();
}
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
return new FutureTask<T>(runnable, value);
}
可以看出来上面的返回值是一个FutureTask。FutureTask是对Future接口的间接实现。中间有个Runnable接口。在这里就不在多说知道它的功能即可(用来追踪Task任务的执行状态)。
最后的线程维护各种东西都是在ThreadPoolExecutor这个类里面进行的
实用举例
public class ThreadPoolDemo {
public static void main(String[] args) {
//单个线程,线程池里面实际只有一个线程在执行
ExecutorService singleThreadExector = Executors.newSingleThreadExecutor();
/*
可重用的线程池:每提交一个任务就创建一个线程,当创建的线程达到指定数量的时候,开始重用
如果某个线程因为异常而结束,它会重新创建一个
*/
ExecutorService fixedThreadExector = Executors.newFixedThreadPool(5);
/*
* 可缓存的线程池,如果线程池的大小超过了处理任务的线程,那么就会回收闲置部分(60秒的时间),
* 当任务增加时,此线程又可以智能的添加新线程来处理任务,此线程池没有大小闲置,完全依赖与操作系统能够创建的最大线程数。
*/
ExecutorService cacheThreadExector = Executors.newCachedThreadPool();
//创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求。
ExecutorService scheduledThreadExector = Executors.newScheduledThreadPool(0);
Thread[] threads = new Thread[10];
for (int count = 0; count < 10; count ++){
final int finalCount = count;
threads[count] = new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println("I'm Thread :"+finalCount +
" time stamp is:" + System.currentTimeMillis());
Thread.sleep(1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
fixedThreadExector.execute(threads[count]);
}
fixedThreadExector.shutdown();
}
}
以上的三种线程池都是基于 ThreadPoolExcutor的。让我们看一下运行效果
对于SingleThreadExcutor;
通过打印出来的时间戳可以明显的知道这是只有一个线程的线性线程池让我们看下源码
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
明显的核心线程数和最大线程数都为1,自然是线性的了。
再看FixedThreadPool..这是一个指定线程数的线程池。对于指定的线程数可以复用。
通过表示出来的。可以看到半部分的5个线程是同时进行的。让我们看下他的源码
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
同上面的singleThreadPool基本是一样的,唯一区别就是指定的线程数。
再看一下CacheThreadPool,再看其效果前让我们先看一下其源码的实现
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
明显的,他的核心线程数为0,最大线程数为0X7fffffffff,任务等待时常为1分钟。另外还可以看到,它的阻塞队列和其他的有些不太一样, 对于SynchronousQueue 简单的说明里面其实就是一个没有数据缓冲的队列。。。只有里面元素在其他Task中remove的时候你才可insert。具体 可以参考下这个文章http://ifeve.com/java-synchronousqueue/
再看看 cacheThreadPool的三次运行结果。通过运行结果我们可以看出,其线程池中的线程数是不定的,通过文档翻译可以知道 Creates a thread pool that creates new threads as needed, but will reuse previously constructed threads when they are available. 在创建必须的线程并且会重用以前构造产生并且可以重用的线程。
通过以上的说明可能对ThreadPoolExcutor有了一定了解