1、什么是线程(Thread)和线程池(ThreadPool) 线程
线程:进程中负责程序执行的执行单元。一个进程至少有一个线程。
线程池:基本思想是对象池的思想,开辟一块内存空间,里面存放一个重操作的对象,里面存放众多的线程,池中的线程执行调度由池管理器来处理,当需要线程执行任务时,从线程池中获取一个,执行完该任务后,将线程重新放入线程池中
2、为什么需要线程池
java的线程是重量级的,如果频繁的创建和销毁会严重影响程序的性能
3、ThreadPoolExecutor
3.1 ThreadPoolExecutor参数
- corePoolSize 核心线程数
- maximumPoolSize 最大线程数
- keepAliveTime 线程空闲存活时间
- workQueue 任务队列
- 无界阻塞队列 比如LinkedBlockingQueue,来多少任务,就放多少任务
- 有界阻塞队列 比如ArrayBlockingQueue,只能存放指定大小的任务
- 同步移交 比如SynchronousQueue不存储任务任务,接收到任务后直接转移 给其他线程
- threadFactory 线程工厂
- handler 拒绝策略
- AbortPolicy:使用这种策略的线程池,将在无法继续接受新任务时,给任务提交方抛出RejectedExecutionException,让他们决定要如何处理;
- CallerRunsPolicy:这个策略,顾名思义,将把任务交给调用方所在的线程去执行;
- DiscardPolicy:直接丢弃掉新来的任务;
- DiscardOldestPolicy:丢弃最旧的一条任务,其实就是丢失blockingQueue.poll()返回的那条任务,要注意,如果你使用的是PriorityBlockingQueue优先级队列作为你的任务队列,那么这个策略将会丢弃优先级最高的任务,所以一般情况下,PriorityBlockingQueue和DiscardOldestPolicy不会同时使用
3.2 Executors的不同类型的线程池
Executors类提供了创建5种经典常用的线程池的静态方法,下面,让我们来分析一下
- newCachedThreadPool
//无参创建cacheThreadPool的方法
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}//传入ThreadFactory作为参数
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
threadFactory);
}复制代码
根据cacheThreadPool的创建参数,我们可以得出它的一些特性,corePoolSize(核心线程数)为0,但是maxmumPoolSize为Integer.MAX_VALUE,这样我们可以认为最大创建的线程数为无穷大。线程空闲销毁时间为60s。任务队列是synchronousQueue,这是一个没有存储空间的队列,一直有一个消费者在等待任务写入,当任务写入后会被立即取出消费,因此,这个线程池的特点是当有任务写入后,会检查当前是否有可用线程,如果有可用线程,则使用该可用线程去执行该任务,如果没有可用线程,则会创建一条线程来执行该任务。任务执行完毕后,该线程在设定的时间内未被再次使用,则会被销毁。
使用场景:实时性要求高,任务多且每个任务耗时少。
- newFixedThreadPool
//参数nThreads 设置当前线程数
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}复制代码
corePoolSize(核心线程数)和maxmumPoolSize(最大线程数)为参数nThread,线程空闲时间为0L,则意味着该线程不会被回收销毁,知道该线程池被shutDown()。workQueue为LinkedBlockingQueue,该队列为无边界队列,最大的存储空间为Integer.MAX_VALUE,可以认为能无限存放任务,因此该线程池的特点是当线程池中的线程数小于核心线程数且当前不存在可用线程,则会优先创建线程,直到线程数等于最大线程数,如果继续添加任务,则会放入队列,直到有可用线程才会处理任务队列中的任务。
使用场景:对实时性要求不高的任务。