线程池的使用
线程池
1.介绍
多线程缺点:
- 处理任务的线程创建和销毁都非常的耗时间并消耗资源
- 多线程之间的切换也会非常耗时并消耗资源
采用线程池的好处
- 使用时线程已经存在,消除了线程创建的消耗
- 通过设置线程数目,防止资源不足
2.ThreadPoolExecutor构造函数参数
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
-
corePoolSize:线程池中核心线程数的最大值,核心线程不会被销毁
-
maximumPoolSize:线程池中能拥有的最大线程数
- 当线程池中最大线程数大于最大核心线程数时,剩下的非核心线程可以被销毁
-
workQueue:用于缓存任务的阻塞队列
- SynchronousQueue
:内部只能包含一个元素,当线程池没有空闲的线程,插入元素到队列的线程会被阻塞,知道有空闲的线程向队列请求任务,入列操作才可以继续进行,然后空闲线程就可以得到元素 - LinkedBockingQueue
:链表实现的队列,可以是有界也可以是无界
- SynchronousQueue
-
阻塞队列是指当核心线程无空闲时,有新的任务进来,就会先添加到阻塞队列等待核心线程空闲
-
上述三者关系:新的任务进来,如果没有空闲线程
- 正在运行的线程数<corePoolSize,则添加新的线程执行
- 正在运行的线程数=corePoolSize,阻塞队列未满,添加到阻塞队列
- 正在运行的线程数<maximumPoolSize,阻塞队列已经满了,创建新的线程执行
- 正在运行的线程数<maximumPoolSize,阻塞队列已经满了,根据构造函数中的handler指定的策略来拒绝新的任务
-
keepAliveTime:表示空闲的线程存活的时间
-
unit:keepAliveTime的单位
-
handler:拒绝新任务采取的策略
ThreadPoolExecutor.ThreadAbortPolicy() 抛出RejectedExecutionException ThreadPoolExecutor.CallerRunsPolicy() 由向线程池提交任务的线程来执行任务 ThreadPoolExecutor.DiscardOldestPolicy() 抛弃最旧的任务(最先提交而没有得到执行的任务) ThreadPoolExecutor.DiscardPolicy() 抛弃当前的任务 -
threadFactory:指定线程创建工厂
3.四种常见的线程池
介绍创建线程的时候我们提到过,javaSE定义了一个Executors类简化我们创建线程池的过程,提供了四个线程池的创建方法
1.newCachedThreadPool
-
可缓存线程池,线程池长度超过处理需要,可以灵活回收空余线程,若无可回收,则新建线程
-
特点:
- 工作线程的创建几乎没有限制(隐形限制为Integer.Max_value)
- 空闲的工作线程可以会销毁,有新任务重新创建
- 使用时要注意控制任务的数量,大量线程同时运行有可能造成系统瘫痪
-
使用
//创建线程池 ExecutorService cachedThreadPool = Executors.newCacheThreadPool(); //启动线程,cachedThreadPool线程只能通过实现Runnable接口的方式实现 cachedThreadPool.execute(new Runnable(){ public void run(){ ………… } });
2.newFixedThreadPool
-
创建一个指定工作线程数量的线程池,每当提交一个任务就创建一个线程,达到线程池最大值则存入到池队列中
-
优点:具有线程池提高程序效率和节省创建线程时所耗的开销
-
缺点:线程池中的空闲线程不会自动销毁,线程池中没有可运行任务时,它不会释放工作线程,还有占用一定的系统资源,适合一直频繁有任务进行且任务量稳定的场景
-
使用
//3为自定义的线程数 ExecutorService fixThreadPool = Executors.newFixedThreadPool(3); //使用方式和缓存线程池类似 fixThreadPool.execute(new Runnable(){ public void run(){ ………… } });
3.newSingleThreadExecutor
- 创建一个单线程化的Executor,即只创建唯一的工作者线程来执行任务,他只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO,LIFO,优先级)执行。如果这个线程异常结束,会有另一个取代他,保证顺序执行
- 单工作线程的最大特点是可保证顺序的执行各个任务,并且在任意给定的时间不会有多个线程是活动的。
- 使用方式类似
4.newScheduleThreadPool
-
定时线程:该方法创建一个定长的线程池,而且支持定时的以及周期性的任务执行
-
使用
//创建定长线程池 ScheduleExecutorService scheduleThreadPool = Executors.scheduleThreadPool(5); //设置启动线程 scheduleThreadPool.schedule(new Runnable(){ public void run(){ ………… } },3,TimeUnit.SECONDS); //两个参数设置延迟时间,数值和单位,这里是3秒