Java的线程池是Java5.0以后的新功能,它让开发者更易开发高效的多线程程序,也让多线程程序的性能大大提高。Java提供的关于线程池的API是基于原有线程API的,只是用另外一种方式来使用Java的多线程编程功能。
简单来说,线程池就是一个或者多个线程的集合。一般而言,线程池有一下几个部分。
那么为什么要使用线程池呢?当短时间内需要处理的任务数量很多时,使用线程池的好处体现在两点,
java.uitl.concurrent.ThreadPoolExecutor类是线程池中最核心的一个类。它的继承关系为主要以下4个ThreadPoolExecutor、AbstractExecutorService、ExecutorService和Executor,
在ThreadPoolExecutor类中提供了四个构造方法:
public class ThreadPoolExecutor extends AbstractExecutorService {
.....
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue);
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory);
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler);
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler);
...
}
它的几个重要的参数的意思,
举个简单的例子:
假如有一个工厂,工厂里面有10个工人,每个工人同时只能做一件任务。因此只要当10个工人中有工人是空闲的,来了任务就分配给空闲的工人做;当10个工人都有任务在做时,如果还来了任务,就把任务进行排队等待;如果说新任务数目增长的速度远远大于工人做任务的速度,那么此时工厂主管可能会想补救措施,比如重新招4个临时工人进来;然后就将任务也分配给这4个临时工人做;如果说着14个工人做任务的速度还是不够,此时工厂主管可能就要考虑不再接收新的任务或者抛弃前面的一些任务了。当这14个工人当中有人空闲时,而新任务增长的速度又比较缓慢,工厂主管可能就考虑辞掉4个临时工了,只保持原来的10个工人,毕竟请额外的工人是要花钱的。
这个例子中的corePoolSize就是10,而maximumPoolSize就是14(10+4)。也就是说corePoolSize就是线程池大小,maximumPoolSize在我看来是线程池的一种补救措施,即任务量突然过大时的一种补救措施。
当任务提交给线程池之后的处理策略,这里总结一下主要有4点:
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadPoolTest {
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 200, TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<Runnable>(5));
for(int i=0;i<15;i++){
MyTask myTask = new MyTask(i);
executor.execute(myTask);
System.out.println("线程池中线程数目:"+executor.getPoolSize()+",队列中等待执行的任务数目:"+
executor.getQueue().size()+",已执行完别的任务数目:"+executor.getCompletedTaskCount());
}
executor.shutdown();
}
}
class MyTask implements Runnable {
private int taskNum;
public MyTask(int num) {
this.taskNum = num;
}
@Override
public void run() {
System.out.println("正在执行task "+taskNum);
try {
Thread.currentThread();
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("task "+taskNum+"执行完毕");
}
}
运行结果
正在执行task 0
线程池中线程数目:1,队列中等待执行的任务数目:0,已执行完别的任务数目:0
线程池中线程数目:2,队列中等待执行的任务数目:0,已执行完别的任务数目:0
正在执行task 1
线程池中线程数目:3,队列中等待执行的任务数目:0,已执行完别的任务数目:0
正在执行task 2
线程池中线程数目:4,队列中等待执行的任务数目:0,已执行完别的任务数目:0
线程池中线程数目:5,队列中等待执行的任务数目:0,已执行完别的任务数目:0
线程池中线程数目:5,队列中等待执行的任务数目:1,已执行完别的任务数目:0
线程池中线程数目:5,队列中等待执行的任务数目:2,已执行完别的任务数目:0
线程池中线程数目:5,队列中等待执行的任务数目:3,已执行完别的任务数目:0
线程池中线程数目:5,队列中等待执行的任务数目:4,已执行完别的任务数目:0
线程池中线程数目:5,队列中等待执行的任务数目:5,已执行完别的任务数目:0
线程池中线程数目:6,队列中等待执行的任务数目:5,已执行完别的任务数目:0
正在执行task 3
线程池中线程数目:7,队列中等待执行的任务数目:5,已执行完别的任务数目:0
正在执行task 11
线程池中线程数目:8,队列中等待执行的任务数目:5,已执行完别的任务数目:0
正在执行task 4
线程池中线程数目:9,队列中等待执行的任务数目:5,已执行完别的任务数目:0
正在执行task 10
线程池中线程数目:10,队列中等待执行的任务数目:5,已执行完别的任务数目:0
正在执行task 12
正在执行task 13
正在执行task 14
task 2执行完毕
正在执行task 5
task 1执行完毕
正在执行task 6
task 0执行完毕
正在执行task 7
task 11执行完毕
task 3执行完毕
正在执行task 9
task 14执行完毕
正在执行task 8
task 13执行完毕
task 12执行完毕
task 10执行完毕
task 4执行完毕
task 5执行完毕
task 7执行完毕
task 6执行完毕
task 8执行完毕
task 9执行完毕
从执行结果可以看出,当线程池中线程的数目大于5时,便将任务放入任务缓存队列里面,当任务缓存队列满了之后,便创建新的线程。如果上面程序中,将for循环中改成执行20个任务,就会抛出任务拒绝异常了。
原文地址:http://blog.csdn.net/wtyvhreal/article/details/46368587