所有 BlockingQueue 都可用于传输和保持提交的任务。可以使用此队列与池大小进行交互:
  • 如果运行的线程少于 corePoolSize,则 Executor 始终首选添加新的线程,而不进行排队。
  • 如果运行的线程等于或多于 corePoolSize,则 Executor 始终首选将请求加入队列,而不添加新的线程。
  • 如果无法将请求加入队列,则创建新的线程,除非创建此线程超出 maximumPoolSize,在这种情况下,任务将被拒绝。
排队有三种通用策略:
  1. 直接提交。工作队列的默认选项是 SynchronousQueue,它将任务直接提交给线程而不保持它们。在此,如果不存在可用于立即运行任务的线程,则试图把任务加入队列将失败,因此会构造一个新的线程。此策略可以避免在处理可能具有内部依赖性的请求集时出现锁。直接提交通常要求无界 maximumPoolSizes 以避免拒绝新提交的任务。当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性。
  2. 无界队列。使用无界队列(例如,不具有预定义容量的 LinkedBlockingQueue)将导致在所有 corePoolSize 线程都忙时新任务在队列中等待。这样,创建的线程就不会超过 corePoolSize。(因此,maximumPoolSize 的值也就无效了。)当每个任务完全独立于其他任务,即任务执行互不影响时,适合于使用无界队列;例如,在 Web 页服务器中。这种排队可用于处理瞬态突发请求,当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性。
  3. 有界队列。当使用有限的 maximumPoolSizes 时,有界队列(如 ArrayBlockingQueue)有助于防止资源耗尽,但是可能较难调整和控制。队列大小和最大池大小可能需要相互折衷:使用大型队列和小型池可以最大限度地降低 CPU 使用率、操作系统资源和上下文切换开销,但是可能导致人工降低吞吐量。如果任务频繁阻塞(例如,如果它们是 I/O 边界),则系统可能为超过您许可的更多线程安排时间。使用小型队列通常要求较大的池大小,CPU 使用率较高,但是可能遇到不可接受的调度开销,这样也会降低吞吐量.
                                           Above from Javadoc1.6

创建线程池,有多种构造函数。如下两种:
/*public ThreadPoolExecutor(int corePoolSize,
      int maximumPoolSize,
      long keepAliveTime, TimeUnit unit,
      BlockingQueue<Runnable> workQueue,
      RejectedExecutionHandler handler)
     */

    ThreadPoolExecutor threadPool = new ThreadPoolExecutor(5, 5, 3,
        TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(100),
        new ThreadPoolExecutor.AbortPolicy());

/*public ThreadPoolExecutor(int corePoolSize,
                                                    int maximumPoolSize,
                                                    long keepAliveTime,
                                                    TimeUnit unit,
                                                    BlockingQueue<Runnable> workQueue)*/

    ThreadPoolExecutor threadPool2 = new ThreadPoolExecutor(5, 8, 1,
        TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
使用LinkedBlockingQueue,即不限队列大小,这时maximumPoolSize无效。池中线程数最多为corePoolSize

下面想要完成这样的功能:
主线程在线程池中所有线程结束后才继续执行或结束。
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;


public class TestThreadPool {
  public static void main(String[] args) {

    System.out.println("main thread started!");    
    /*public ThreadPoolExecutor(int corePoolSize,
                                                    int maximumPoolSize,
                                                    long keepAliveTime,
                                                    TimeUnit unit,
                                                    BlockingQueue<Runnable> workQueue)*/

    ThreadPoolExecutor threadPool2 = new ThreadPoolExecutor(5, 8, 1,
        TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
    for (int i = 0; i < 10; i++) {   
      threadPool2.execute(new Task(i));
    }
    threadPool2.shutdown(); //关闭后不能加入新线程,队列中的线程则依次执行完
    while(threadPool2.getPoolSize()!=0);
    System.out.println("main thread end!");
  }
}

class Task implements Runnable{
  int count;
  Task(int i){
    this.count = i;
  }
  public void run() {
    try {
      System.out.println("in thread "+count);
      Thread.sleep(10000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }    

    System.out.println("    thread "+count+" end!");
  }  
}
/*
 main thread started!
in thread 1
in thread 0
in thread 2
in thread 3
in thread 4
  thread 1 end!
in thread 5
  thread 3 end!
in thread 6
  thread 2 end!
in thread 7
  thread 0 end!
in thread 8
  thread 4 end!
in thread 9
  thread 5 end!
  thread 8 end!
  thread 7 end!
  thread 6 end!
  thread 9 end!
main thread end!
 */
采用的是getPoolSize()返回当前池中的线程数,程序也说明shutdown虽然关闭线程池操作,但只是不加入新线程,而线程池队列中的线程仍将继续执行完成后,才会最后关闭。因此在池中线程未结束时当前线程数不为0.

原来使用thread.join(),在不用线程池时很容易使用,join()似乎要在thread.start()后才能有效,而线程池则直接用threadPool.execute(runnable or thread),用join()无效。
    for (int i = 0; i < 10; i++) {
      Thread t = new Thread(new Task(i), "thread " + i);      
      threadPool2.execute(new Task(i));
      //t.start();
      try {
        t.join();//never effective
      } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }
    threadPool2.shutdown(); //关闭后不能加入新线程,队列中的线程则依次执行完
    //threadPool2.shutdownNow(); //立即中断停止线程执行,返回等待执行的任务列表
    System.out.println("main thread end!");
/*
main thread started!
in thread 0
in thread 1
main thread end!
in thread 2
in thread 3
in thread 4
  thread 1 end!
in thread 5
  thread 0 end!
in thread 6
  thread 4 end!
in thread 7
  thread 3 end!
in thread 8
  thread 2 end!
in thread 9
  thread 5 end!
  thread 6 end!
  thread 9 end!
  thread 8 end!
  thread 7 end!
 */

今天发现threadPoolExecutor.isTerminated()可以代替比较,该函数表示如果关闭后所有任务都已完成,则返回 true。另一函数threadPoolExecutor.isTerminating()则表示如果此执行程序处于在 shutdown 或 shutdownNow 之后正在终止但尚未完全终止的过程中,则返回 true。