为了能够更好的进行多线程编程,JDK提供了一套Executor执行框架,简化开发人员的对多线程的编程工作。
其框架结构图如下:
框架图比较庞大,但我们只需要关注如下几个实现:
我们平时用的最多的便是 Executors工厂类,这个工厂类提供了能产生多个不同功能线程池的方法。
自定义线程池
newFixedThreadPool()、newSingleThreadExecutor()和newCachedThreadPool()方法其内部都使用了 ThreadPoolExecutor线程池。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue());
}
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue(),
threadFactory);
}
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue()));
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
workQueue用来盛放被提交但未执行的任务队列,它是一个BlockingQueue 接口的对象,仅用于存放 Runnable对象。可以使用以下一种阻塞队列
直接提交队列:由SynchronousQueue 对象提供。即每一次提交任务时,如果没有空闲的线程,就会提交失败或者执行拒绝策略。因此,此时要设置很大的maximumPoolSize值。
有界的任务队列:可以使用 ArrayBlockingQueue。这时,如果有新任务需要执行,且实际线程数小于corePoolSize 时,会优先创建线程。若大于corePoolSize,则会将任务加入等待队列。若队列已满,则会创建新线程且保证线程数不大于 maximumPoolSize。若大于 maximumPoolSize,则执行拒绝策略。
无界任务队列:使用 LinkedBlockingQueue 类实现。和有界任务队列类似,只不过系统线程数到达corePoolSize后就不在增加。后续任务都会放入阻塞队列中,直到耗尽系统资源。
优先任务队列: 通过 PriorityBlockingQueue 实现。可以控制任务的执行先后顺序,是一个特殊的无界队列。
ThreadPoolExecutor 最后一个参数 handler 指定了拒绝策略,有如下几种:
以上拒绝策略都实现了 RejectedExecutionHandler 接口,我们也可以扩展这个接口来实现自己的拒绝策略。
下面,我们使用优先队列自定义线程池来实现具有优先级调度功能的线程池。使用优先队列时,任务线程必须实现 Comparable 接口。
package executor;
import java.util.concurrent.Executor;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class MyThread implements Runnable,Comparable{
private String name;
public MyThread(String name){
this.name=name;
}
public MyThread(){
name="";
}
@Override
public void run(){
try{
Thread.sleep(100);
System.out.println(name+" running....");
}catch(InterruptedException e){
e.printStackTrace();
}
}
@Override
public int compareTo(MyThread o){
int me = Integer.valueOf(name.split("_")[1]);
int other = Integer.valueOf(o.name.split("_")[1]);
return me-other;
}
public static void main(String[] args){
Executor exe = new ThreadPoolExecutor(100, 100, 0L, TimeUnit.SECONDS, new PriorityBlockingQueue());
for(int i =0;i<1000;i++){
exe.execute(new MyThread("testThread_"+(999-i)));
}
}
}
testThread_998 running....
testThread_999 running....
testThread_993 running....
testThread_995 running....
testThread_997 running....
。。。
testThread_912 running....
testThread_900 running....
testThread_910 running....
testThread_1 running....
testThread_2 running....
testThread_3 running....
testThread_4 running....
testThread_0 running....
扩展ThreadPoolExecutor
ThreadPoolExecutor 也是一个可以扩展的线程池,它提供了 beforeExecute()、afterExecute()和terminated()3个接口对其进行控制。
在 Worker.runWorker() 的方法内部提供了这样一个调用过程:
try {
beforeExecute(wt, task);
Throwable thrown = null;
try {
task.run();
} catch (RuntimeException x) {
thrown = x; throw x;
} catch (Error x) {
thrown = x; throw x;
} catch (Throwable x) {
thrown = x; throw new Error(x);
} finally {
afterExecute(task, thrown);
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
class MyThreadPoolExecutor extends ThreadPoolExecutor {
public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
long keepAliveTime, TimeUnit unit, BlockingQueue workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
protected void beforeExecute(Thread t, Runnable r) {
System.out.println("beforeExecute MyThread name:" + t.getName()
+ " ID:" + t.getId());
}
protected void afterExecute(Runnable r, Throwable t) {
System.out.println("afterExecute MyThread name:" + Thread.currentThread().getName() + " ID:"
+ Thread.currentThread().getId());
System.out.println("afterExecute PoolSize:" + this.getPoolSize());
}
}