要用到线程池,就要先介绍一个类:ThreadPoolExecutor.
通过查看源码发现继承及实现关系为
在ThreadPoolExecutor类中,发现有四种构造方法,需要传入很多参数。
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {
    if (corePoolSize < 0 ||
        maximumPoolSize <= 0 ||
        maximumPoolSize < corePoolSize ||
        keepAliveTime < 0)
        throw new IllegalArgumentException();
    if (workQueue == null || threadFactory == null || handler == null)
        throw new NullPointerException();
    this.acc = System.getSecurityManager() == null ?
            null :
            AccessController.getContext();
    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}
实例化一个ThreadPoolExecutor类
ThreadPoolExecutor executor=new ThreadPoolExecutor(5, 10, 200, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>,5));
核心池大小为5,线程池大小为10,线程允许空闲200ms,阻塞队列大小5.
然后,创建20个线程并每次打印线程池中的状态
for(int a=0;a<20;a++) {
    executor.execute(new ThreadPoolT(a));
    System.out.println("线程池中线程数目"+executor.getPoolSize()+"正在等待执行的任务数目"+executor.getQueue().size()+"已经执行完的任务数目:"+executor.getCompletedTaskCount());
}
其中线程的run方法为
    @Override
public void run() {
    // TODO Auto-generated method stub
    System.out.print("线程"+id+"正在执行...");
    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    System.out.println("线程"+id+"结束..");
}
关闭线程池
executor.shutdown();
总代码
package com.test;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadPoolT implements Runnable{
    private int id;
    public ThreadPoolT(int id) {
        super();
        this.id = id;
    }
    public static void main(String[] args) {
        ThreadPoolExecutor executor=new ThreadPoolExecutor(5, 10, 200, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(5));
        for(int a=0;a<20;a++) {
            executor.execute(new ThreadPoolT(a));
            System.out.println("线程池中线程数目"+executor.getPoolSize()+"正在等待执行的任务数目"+executor.getQueue().size()+"已经执行完的任务数目:"+executor.getCompletedTaskCount());
        }
        System.out.println(executor.getLargestPoolSize());
        System.out.println(executor.getPoolSize());
        executor.shutdown();
    }
    @Override
    public void run() {
        // TODO Auto-generated method stub
        System.out.print("线程"+id+"正在执行...");
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println("线程"+id+"结束..");
    }
}

可见
如果把前面的队列里的参数5去掉,并在线程池结束前加下列代码:
Thread.sleep(10000);
System.out.println(executor.getPoolSize()+"AAAAAAAAAAAAAAA");
executor.shutdown();
则运行结果为:

可见线程全部运行结束后核心池仍有5个线程,这便是线程池使用的优点,不用频繁开线程关线程,而是提供一些线程代理运行需要运行的线程,提高了程序效率。
另外,其实一般使用线程池不用我们每次指定那么多参数。一般使用Executors类中提供的静态方法来创建线程池:
//corePoolSize和maximumPoolSize值相等,它使用LinkedBlockingQueue
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>(),
                                  threadFactory);
}
//corePoolSize和maximumPoolSize都设置为1,使用LinkedBlockingQueue
public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}
//corePoolSize设置为0,maximumPoolSize设置为Integer.MAX_VALUE,使用SynchronousQueue,也就是说来了任务就创建线程运行,当线程空闲超过60秒,就销毁线程
public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}
(1)高并发、任务执行时间短的业务,线程池线程数可以设置为CPU核数+1,减少线程上下文的切换
(2)并发不高、任务执行时间长的业务要区分开看:
  a)假如是业务时间长集中在IO操作上,也就是IO密集型的任务,因为IO操作并不占用CPU,所以不要让所有的CPU闲下来,可以适当加大线程池中的线程数目,让CPU处理更多的业务 (2*cpu核心)
  b)假如是业务时间长集中在计算操作上,也就是计算密集型任务,这个就没办法了,和(1)一样吧,线程池中的线程数设置得少一些,减少线程上下文的切换