1、总共有5种线程池:
- 1、单个线程 - ExecutorService pool1 = Executors.newSingleThreadExecutor();  
- 2、固定数量线程 - ExecutorService pool2 = Executors.newFixedThreadPool(2);  
- 3、动态线程数量 - ExecutorService pool3 = Executors.newCachedThreadPool();  
- 4、定时调度的线程池,功能和timer一样 - ExecutorService pool4 = Executors.newScheduledThreadPool(2);   - ScheduledThreadPoolExecutor还是继承了ThreadPoolExecutor  
- 5、这个不知道是什么线程池 - ExecutorService pool5 = Executors.newWorkStealingPool();  
它们都有execute()、submit()等方法。


在getTask中有这么一段代码

我们执行它的execute()方法其实只是把任务放在它里面的blockingqueue中,这样就会唤醒阻塞的线程拿到task来执行,所以这就需要blockingqueue。这是一个生产者和消费者模型
2、问题:怎么知道queue中的任务怎么运行?
这就需要统一的接口标准,往里面扔的任务必须implements Runable接口才行(为什么?)
因为:只要实现了Runable/callable接口,就必须实现一个run/call方法,这样线程池中的线程就可以直接调用run或者call方法,执行业务。
注意:传入进去的Runnable任务,不会以线程的形式运行。
3、代码实例:
import java.util.ArrayList;
import java.util.concurrent.*;
/**
 * Executors创建线程池
 * ThreadPoolExecutor创建线程池
 *
 * 类的关系
 * class ThreadPoolExecutor extends AbstractExecutorService
 *
 * class AbstractExecutorService implements ExecutorService
 *
 * interface ExecutorService extends Executor
 *
 * [@Author](https://my.oschina.net/arthor) liufu
 * @CreateTime 2018/5/10  15:24
 */
public class ThreadPoolExecutorTest {
    public static void main(String[] args) {
        ExecutorService pool1 = Executors.newFixedThreadPool(2);
        ExecutorService pool2 = Executors.newCachedThreadPool();
        ExecutorService pool3 = Executors.newScheduledThreadPool(2);
        ExecutorService pool4 = Executors.newSingleThreadExecutor();
        ExecutorService pool5 = Executors.newWorkStealingPool();
       //Executors.newXX其实就是创建了new ThreadPoolExecutor()对象,里面传入对应的值而已
       //推荐使用这种方式,对资源好控制
        ExecutorService executor = new ThreadPoolExecutor(2,  //最小线程数        
                2,                         //最大线程数
                0L,                         //执行超时,0L,表示不超时
                TimeUnit.MILLISECONDS,                      //时间为分钟
                new ArrayBlockingQueue<Runnable>(10));        //任务队列的大小
        ArrayList<Runnable> runnables = new ArrayList<>();
        pool1.shutdown();
        //这个就是生产者!!
        for (int i = 0; i < 100; i++) {
            runnables.add(new Runnable() {
                [@Override](https://my.oschina.net/u/1162528)
                public void run() {
                    try {
                        System.out.println(Thread.currentThread().getName());
                        Thread.sleep(5000);
                        System.out.println("工作完成!!");
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            });
        }
        //消费者!!!
        for (Runnable runnable : runnables) {
            pool1.execute(runnable);
        }
        //主线程是不等待线程池的。
        System.out.println("早就执行完了,不等待线程池的处理了");
    }
}
4、线程池示意图

5、问题
- 1、为什么需要线程池? - 这个和连接池一样,为了避免频繁的创建和销毁线程池带来的性能损耗。 
- 2、它的execute()方法其实只是把任务放在它里面的BlookingQueue中,然后线程池里面的线程来获取任务执行,如果queue中没有任务就阻塞。 
- 3、线程池创建的方式 
- 3.1、Excutors - 内部new ThreadPoolExcutor(),而且那个任务队列queue是没有指定大小的,默认是Integer.MAX_VALUE = 42亿,如果线程处理的慢,就会导致queue堆满42亿任务对象,会出现内存溢出问题,GC没法扫。 
- 3.2、new ThreadPoolExcutor()这种比较自主可控,里面有7个参数 - 前面5个比较常用分别是: - 最小线程 最大线程 过期时间 时间单位 queue(要指定大小)
- 后面是: - ThreadFactory(可以给线程加名字) RejectedExecutionHandler(拒绝执行时的回调)。
- RejectedExecutionHandler已经有好几种实现 - ● AbortPolicy ● DiscardPolicy ● DiscardOldestPolicy ● CallerRunsPolicy ● 自定义 
 

 
  
  
  
 
 
  
 
 
 