1、线程池的概念
2、线程池的创建都是工厂方法。我们不要直接去 new 线程池,因为线程池的创建还要作很多的准备工作。
3、常见线程池:
(1)newCachedThreadPool():创建一个具有缓存功能的线程池,可根据任务需要动态创建线程,来执行任务。若线程池中有空闲的线程将重用该线程来执行任务。没有空闲的则创建新线程来完成任务。理论上池子里可以放 int 最大值个线程。缓存线程生命周期1分钟,得不到任务直接kill
(2)newFixedThreadPool(int nThreads):创建一个可重用的、具有固定线程数的线程池。池中的线程数是固定的。若所有线程处于饱和状态,新任务将排队等待。
(3)newScheduledThreadPool(int corePoolSize):创建具有指定线程数的线程池。它可以在指定时间延迟后执行线程任务,可将带运行的任务延迟指定时长后再运行。corePoolSize指池中所保存的线程数,即使线程是空闲的也要被保存在线程池内。
BlockingQueue:解决了读写数据阻塞问题,但是同时写或读还是同步的。
(1)双缓冲队列加快了读写数据操作,双缓冲对列可以规定队列存储元素的大小,一旦队列中的元素达到最大值,待插入的元素将等待。等待时间是给定的,当给定时间到了元素还没有机会被放入队列那么会抛出超时异常。
(2) LinkedBlockingQueue 是一个可以不指定队列大小的双缓冲队列。若指定大小,当达到峰值后,待入队的将等待。理论上最大值为int最大值。
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
corePoolSize:核心池的大小,这个参数跟后面讲述的线程池的实现原理有非常大的关系。在创建了线程池后,默认情况下,线程池中并没有任何线程,而是等待有任务到来才创建线程去执行任务,除非调用了prestartAllCoreThreads()或者prestartCoreThread()方法,从这2个方法的名字就可以看出,是预创建线程的意思,即在没有任务到来之前就创建corePoolSize个线程或者一个线程。默认情况下,在创建了线程池后,线程池中的线程数为0,当有任务来之后,就会创建一个线程去执行任务,当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中
maximumPoolSize:线程池最大线程数,这个参数也是一个非常重要的参数,它表示在线程池中最多能创建多少个线程
keepAliveTime:表示线程没有任务执行时最多保持多久时间会终止。默认情况下,只有当线程池中的线程数大于corePoolSize时,keepAliveTime才会起作用,直到线程池中的线程数不大于corePoolSize,即当线程池中的线程数大于corePoolSize时,如果一个线程空闲的时间达到keepAliveTime,则会终止,直到线程池中的线程数不超过corePoolSize。但是如果调用了allowCoreThreadTimeOut(boolean)方法,在线程池中的线程数不大于corePoolSize时,keepAliveTime参数也会起作用,直到线程池中的线程数为0;
(2)LinkedBlockingQueue;
ArrayBlockingQueue和PriorityBlockingQueue使用较少,一般使用LinkedBlockingQueue和SynchronousQueue。线程池的排队策略与BlockingQueue有关。
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务