为什么要有线程池来,可以参考这篇Blog Java线程实现原理
首先来简单看下Java中两种启动线程的方式。
//Extends Thread
public class MyThread extends Thread {
@Override
public void run(){
//TODO
}
public void main(String[] args){
new MyThread().start();
}
}
// Implements Runnable
public class MyRunnable implements Runnable{
@Override
public void run(){
//TODO
}
public void main(String[] args){
new Thread(new MyRunnable()).start();
}
}
第一种方式需要继承一个Thread类,来扩展Thread的类的功能已达到运行自身逻辑的目的,从软件设计上来看这种方式使用继承来扩展功能,不是推荐的做法;从Java语言特性上来说,单继承的规约限制了MyThread的对其他类的功能的复用。因此这种方式看似简单,但是不是推荐启动线程的方法。
第二种方式通过集成Runnable接口实现其run方法完成业务逻辑的编写,并将MyRunnable的实例传给一个Thread实例,并调用Thread实例的start方法进行线程的启动。这种做法的好处是将逻辑功能与线程本事解耦出来,业务逻辑不用受到Thread的类的限制。因此这种方式算是比较合理的方式。
但是这两种方式的一个共同特点是自己启动一个Thread来运行,结合Java线程实现原理来看,Java的线程其实是映射为Linux的一个内核线程来实现的,因而线程的个数也收到了限制,同事过多的启动线程来完成任务也会找成CPU频繁的进行上下文切换造成服务器不稳定,资源分配不合理。为了解决这个问题Java线程池应允而生。
本文只介绍ThreadPoolExecutor因此本文涉及的类的继承结构如下所示:
两个比较重要的类
Executors: 快速创建ThreadPoolExecutor的工具类
ThreadPoolExecutor: 这正的线程池实现者
废话不说,先看一个实例。
public class ThreadPoolTest{
private static ExecutorService executorService = Executors.newFixedThreadPool(5);
public static void main(String[] args){
executorService.execute(new MyRunnable());
}
}
怎么样使用起来简单易懂。
在来看看ThreadPoolExecutor的构造方法
/**
* Creates a new {@code ThreadPoolExecutor} with the given initial
* parameters.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @param maximumPoolSize the maximum number of threads to allow in the
* pool
* @param keepAliveTime when the number of threads is greater than
* the core, this is the maximum time that excess idle threads
* will wait for new tasks before terminating.
* @param unit the time unit for the {@code keepAliveTime} argument
* @param workQueue the queue to use for holding tasks before they are
* executed. This queue will hold only the {@code Runnable}
* tasks submitted by the {@code execute} method.
* @param threadFactory the factory to use when the executor
* creates a new thread
* @param handler the handler to use when execution is blocked
* because the thread bounds and queue capacities are reached
* @throws IllegalArgumentException if one of the following holds:<br>
* {@code corePoolSize < 0}<br>
* {@code keepAliveTime < 0}<br>
* {@code maximumPoolSize <= 0}<br>
* {@code maximumPoolSize < corePoolSize}
* @throws NullPointerException if {@code workQueue}
* or {@code threadFactory} or {@code handler} is null
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
注释已经对这些参数解释的足够清晰,但是要真是使用起来,new出一个ThreadPoolExecutor实例也是比较麻烦的,好在Executors工具类提供了三个适合常见场景的工厂方法,使用起来非常方便快捷。
public static ExecutorService newFixedThreadPool(int nThreads);
public static ExecutorService newSingleThreadExecutor();
public static ExecutorService newCachedThreadPool();