多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。
线程池主要用来解决线程生命周期开销问题和资源不足问题。通过对多个任务重用线程,线程创建的开销就被分摊到了多个任务上了,而且由于在请求到达时线程已经存在,所以消除了线程创建所带来的延迟。这样,就可以立即为请求服务,使应用程序响应更快。另外,通过适当地调整线程池中的线程数目可以防止出现资源不足的情况。
JDK5中提供的Executors工具类可以通过4个静态方法创建4种线程池,如下所示:
(1)Executors.newCachedThreadPool();
public static ExecutorService newCachedThreadPool(){
return new ThreadPoolExecutor(0,Integer.MAX_VALUE,60L,TimeUnit.MILLISECONDS,new SynchronousQueue<Runnable>());
}
- 它是一个可以无限扩大的线程池;
- 它比较适合处理执行时间比较小的任务;
- corePoolSize为0,maximumPoolSize为无限大,意味着线程数量可以无限大;
- keepAliveTime为60S,意味着线程空闲时间超过60S就会被杀死;
- 采用SynchronousQueue接收请求任务,这个阻塞队列没有存储空间,这意味着只要有请求到来,就必须要找到一条工作线程处理予以,如果当前没有空闲的线程,就会再创建一条新的线程。
(2)Executors.newFixedThreadPool ();
public static ExecutorService newFixedThreadPool(int nThreads){
return new ThreadPoolExecutor(nThreads,nThreads,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
}
- 它是一种固定大小的线程池;
- corePoolSize和maximunPoolSize都为用户设定的线程数量nThreads;
- keepAliveTime为0,意味着一旦有多余的空闲线程,就会被立即停止掉;但这里keepAliveTime无效;
- 阻塞队列采用了LinkedBlockingQueue,它是一个*队列;
- 由于阻塞队列是一个*队列,因此永远不可能拒绝任务;
- 由于采用了*队列,实际线程数量将永远维持在nThreads,因此maximumPoolSize和keepAliveTime将无效。
(3)Executors.newScheduledThreadPool();
它用来处理延时任务或定时任务。
它接收SchduledFutureTask类型的任务,有两种提交任务的方式:
①scheduledAtFixedRate
②scheduledWithFixedDelay
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
scheduledThreadPool.schedule(new Runnable() { @Override
public void run() {
System.out.println("delay 3 seconds");
}
}, 3, TimeUnit.SECONDS);
表示延迟3秒执行。
scheduledThreadPool.scheduleAtFixedRate(new Runnable() { @Override
public void run() {
System.out.println("delay 1 seconds, and excute every 3 seconds");
}
}, 1, 3, TimeUnit.SECONDS);
表示延迟1秒后每3秒执行一次。
ScheduledExecutorService比Timer更安全,功能更强大。
(4)Executors.newSingleThreadExecutor();
public static ExecutorService newSingleThreadExecutor(){
return new ThreadPoolExecutor(1,1,0L,TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
}
创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
final int index = i;
singleThreadExecutor.execute(new Runnable() { @Override
public void run() {
try {
System.out.println(index);
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
结果依次输出,相当于顺序执行各个任务。
现行大多数GUI程序都是单线程的。
线程池的作用:
减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。根 据系统的环境情况,可以自动或手动设置线程数量,从而达到运行的最佳效果。