/**
* Executors的好处:可创建固定数量线程的线程池,并可以重用线程池中的线程,减少创建对象, 销毁对象,节省资源
* 并且支持线程定时,中断操作,可控制并发的线程数量
* 而new Thread,在调用run方法后,如果里面的任务执行完毕, 则这个线程会自动关闭了,如果下次还想用
* 则需要再次new Thread,重新创建, 不断创建的话, 会占用较多的资源,可能会造成oom,而且 每个线程不易于统一管理
execute和submit比较
* execute 执行不需要返回值的任务
* submit 执行需要返回值的, 返回Future 对象,通过Future 的get方法获返回值,当调用get方法时,当前线程阻塞,直到任务完成
*
* 执行execute时,是在ThreadPoolExecutor这个类中,主要分为三步
* 1.先判断当前线程数量是否大于核心线程数,如果小于,则创建线程开始执行任务,如果大于则进入BlockingQueue<Runnable> 队列 排队
* 2.进入排队后,再次进行检查状态(因为有些线程步骤1检查后就死了,或者线程池关闭了),线程池若没有线程则创建新的线程, 线程池关闭,则回滚入队列
* 3.如果队列满了, 无法进入队列,就尝试开启新的线程, 则判断如果线程池线程满了,也就是达到最大线程数,这时候就执行拒绝策略,
* 如果开启新的线程成功,则就入新队列
* 而在执行execute的三步中,最主要的方法就是addWorker----worker----getTask
*
* new Thread().start()在一旦执行起来之后,只有在执行完毕后才线程才进入stop状态,不能再次start,如果想在重新复用,只能在
* runnable中下手,可以用死循环一直执行runnable.run的方法,在run的时候检查是否有新的任务进来, 有新任务,就执行新任务的run方法,
* 如果有多个新任务, 就把多个任务的run串联起来,一个个的去执行,没有新任务的时候,就进入队列阻塞,
* Executors真正的最底层核心 就是这个
*/
public class ThreadPoolUtils {
private ScheduledExecutorService scheduledExecutorService;
private ExecutorService fixedThreadPool;
/*--------------------------定时线程------------------------------------------------------------------*/
/**
* 开启固定数量线程的线程池
* 也支持开启定时的线程池
* 这里就传 1, 模拟只支持一个线程的线程池
* @param runnable
* @param start 开始几秒后执行第一次
* @param delay 第一次之后,每次间隔时间delay后,执行下一次
* 默认使用秒
*/
public void startTimerPool(Runnable runnable,long start,long delay){
scheduledExecutorService = Executors.newScheduledThreadPool(1);
scheduledExecutorService.scheduleWithFixedDelay(runnable,start,delay, TimeUnit.SECONDS);
}
/**
* 关闭定时的线程池
*/
public void stopTimerPool(){
scheduledExecutorService.shutdown();
scheduledExecutorService = null;
}
/*------------------------------------缓存线程,尽量少用--------------------------------------------------------*/
/**
* 创建缓存线程池,如果第一个线程任务完成, 则第二个线程会复用第一个线程,不会开启新线程,若第一个没完成,则第二个开启新线程去做
* 超过60s没用的线程 会默认销毁
* 适用于大流量但是周期短的异步处理
*
* 容易出现OOM,因为线程量大,每个线程占用内容多,就会出现oom
* 1w个线程,每个线程占1M,这就是10G,但是电脑是8G的,就oom了
*
* 这种线程池 能少用就少用
*/
public void startCachePool(Runnable... runnables){
if (null == runnables)return;
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i=0;i<runnables.length;i++){
executorService.execute(runnables[i]);
}
}
/*------------------------------------固定线程数量的线程池---------------------------------------------------*/
/**
* 创建定长的线程数的线程池,线程数量可控制的并发
* 超过规定的并发量 就排队等着
* 和CachedThreadPool不同,她的线程不会自动销毁
*
* @param poolSize 线程的数量
*/
public void startFixedPool(int poolSize,Runnable... runnable){
fixedThreadPool = Executors.newFixedThreadPool(poolSize);
for (int i = 0;i<runnable.length;i++){
fixedThreadPool.execute(runnable[i]);
}
}
/**
* 关闭线程池
*/
public void stopFixedPool(){
if (null == fixedThreadPool)return;
fixedThreadPool.shutdown();
fixedThreadPool = null;
}
/*------------------------------------单一线程数量的线程池---------------------------------------------------*/
/**
* 创建唯一的线程来执行,任务顺序执行,一个执行完后执行下一个
* @param runnable
*/
public void startSinglePool(Runnable runnable){
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(runnable);
}
}