线程池的优点
减低资源消耗:通过重复利用已创建的线程降低线程创建和销毁带来的消耗
提高响应速度:当任务到达时,任务可以不需要等待线程创建就能立即执行
提高线程的可管理性:使用线程池可以统一进行线程分配,调度和监控
线程池的工作流程
当一个任务提交给线程池时,
- 首先判断核心池的线程数量是否达到corePoolSize,若未达到,线程池创建新的线程执行任务并将其置入核心池中。否则,判断核心池是否有空闲线程,若有,分配任务执行,否则进入步骤2.
- 判断当前线程池中线程数量有没有达到线程池的最大数量(maximumPoolSize),若没有,创建新的线程执行任务并将其置入线程池中,否则,进入步骤3.
- 判断阻塞队列是否已满,若未满,将任务置入阻塞队列中等待调度。否则,进入步骤4.
- 调用相应的拒绝策略打回任务(有四种拒绝策略,默认为抛出异常给用户AbortPolicy)
工作线程:线程池创建线程时,会将线程封装成工作线程Worker,Worker在执行完成任务后,还会循环获取工作队列的任务来执行
线程池的两大接口
ExcecutorService:普通线程池(Executor的子接口)
- 父类(Executor)方法:void execute(Runnable command);
- 本类方法:<T> Future<T> submit(Callable<T> task);
- 本类方法:Future<?> submit(Runnable task);
- 本类方法:<T> Future<T> submit(Runnable task, T result);
ScheduledExecutorService:定时线程池(ExcecutorService的子接口)
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
long initialDelay,
long period,
TimeUnit unit);
public <V> ScheduledFuture<V> schedule(Callable<V> callable,
long delay, TimeUnit unit);
线程池的创建
ThreadPoolExecutor:(ExecutorService的子类)
ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler)
创建一个线程池
ThreadPoolExecutor threadPoolExecutor =
new ThreadPoolExecutor(3,5,2000,TimeUnit.MILLISECONDS,
new LinkedBlockingDeque<Runnable>())
向线程池提交一个任务
- void execute(Runnable command);
- <T> Future<T> submit(Callable<T> task);
- Future<?> submit(Runnable task);
关闭线程池
- threadPoolExecutor.shutdown();
合理配置线程池
CPU密集型任务(大数运算):NCPU + 1
IO密集型任务(读写文件):2*NCpu
内置的四大线程池
Exectors - 线程池的工具类
1.固定大小线程池
适用于负载较重的服务器(配置较低),来满足资源分配的要求
Exectors.newFixedThreadPool(int nThreads)
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
2.单线程池-只有一个线程
当多线程场景下需要让任务串行执行
Exectors.newSingleThreadExecutor()
new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
3.缓存线程池
适用于负载较轻的服务器,或执行很多短期的异步任务
Executors.newCachedThreadPool()
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
- 当任务提交速度 > 线程执行速度,会不断创建新线程(有可能无限创建线程将内存写满)
- 当线程的执行速度 > 任务提交速度,只会创建若干个有限线程
4.定时调度池
Executors.newScheduledThreadPool(int nThreads);
new ScheduledThreadPoolExecutor(corePoolSize);
//延迟delay个时间单元后创建nThreads个线程执行command任务
executorService.schedule(Runnable command,
long delay, TimeUnit unit);
//延迟delay个单元后每隔period时间单元就执行一次command任务
scheduleAtFixedRate(Runnable command,
long initialDelay,
long period,
TimeUnit unit);