线程池
线程池可以理解为是一个池子，里面存储多个线程。
线程池在启动的时候，会创建大量的空闲线程，当我们向线程池提交任务的时候
线程池就会启动一个线程来处理任务。等任务处理完毕后，线程不会死亡，
而是再次返回到线程池中，成为空闲状态，等待执行下一次任务。
线程池设计思路：
1、准备一个任务容器
2、一次性启动多个消费者线程
3、刚开始任务容器是空的，所以所有消费者线程都是wait()等待状态
4、直到一个外部线程(生产者)向这个任务容器扔了一个任务，就会有一个消费者线程被唤醒。
5、这个消费者线程取出任务，并且执行这个任务，执行完毕后，会再次进入等待状态，继续等待下一个任务。

Java为我们提供了很多的线程池：
ExecutorService newCachedThreadPool();方法创建一个默认的线程池
ExecutorService newFixedThreadPool(int nThreads)    创建一个线程池，指定核心线程数和最大线程数
刚开始创建线程池的时候，并不会自动的创建线程放进线程池，直到有任务需要线程执行，才会创建线程来执行任务。

ThreadPoolExecutor 这个线程池对象我们用的更多一些
ThreadPoolExecutor pool=new ThreadPoolExecutor(核心线程数，最大线程数，空闲线程最大存活时间，时间单位，任务队列，线程工厂，任务拒绝策略)
    1、核心线程数     -->不能小于0
    2、最大线程数     -->不能小于等于0，最大线程数必须大于或等于核心线程数
    3、空闲线程最大存活时间    -->不能小于0
    4、时间单位      -->时间单位
    5、任务队列      -->不能为null
    6、线程工厂      -->不能为null
    7、任务拒绝策略    -->不能为null

线程池的任务拒绝策略：
    1、ThreadPoolExecutor.AbortPolicy类 默认的拒绝策略，丢掉任务，并且抛出RejectedExecutionException异常
    2、ThreadPoolExecutor.DiscardPolicy类 丢弃任务，但是不抛出任何异常， 不建议使用。
    3、ThreadPoolExecutor.DiscardOldestPolicy    丢弃队列中等待最久的任务，然后把当前的任务加入到队列。
    4、ThreadPoolExecutor.CallerRunsPolicy   调用任务的run()方法，绕过线程池直接运行。

ThreadPoolExecutor pool = new ThreadPoolExecutor(
                2,
                5,
                20,
                TimeUnit.MICROSECONDS,
                new ArrayBlockingQueue<>(10),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.DiscardPolicy());    //设置拒绝策略

线程池最多可以执行的任务数=任务队列的容量+最大线程数









