目录
创建线程的方法
- 实现Runnable接口- 实现Callable接口- 继承Thread类
为什么要使用线程池
- 降低资源消耗,减少创建线程的开销- 提高响应速度,新任务可以由空闲线程立刻执行- 可管理性,线程池统一管理
创建线程池的方法
Executors类提供了几个静态方法用于创建线程池
- newSingleThreadExecutor(),核心池大小为1,LinkedBlockingQueue(最大)- newFixedThreadPool(n),指定核心池大小为- newCachedThreadPool(),- newScheduledThreadPool(),定时任务,有多线程实现和单线程实现
不建议使用Executors提供的几种线程池而要使用ThreadPoolExecutor的构造方法指定参数
防止OOM,Executors提供的几种线程池的等待队列没有设置大小限制(最大),可能会造成OOM,所以一般使用ThreadPoolExecutor的构造方法创建线程池:
public class ThreadPoolExecutor extends AbstractExecutorService { ..... public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueueworkQueue); public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue workQueue,ThreadFactory threadFactory); public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue workQueue,RejectedExecutionHandler handler); public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler); ...}
线程池的参数
- corePoolSize:核心池大小- maximumPoolSize:最大线程数- keepAliveTime:线程的空闲时间- unit:空闲时间的单位(时分秒毫秒)- workQueue:等待队列/阻塞队列,有多种类型- threadFactory:线程工厂,用来创建线程- handler:拒绝策略,多种类型
线程池的状态
running=0shutdown=1stop=2terminated=3
调用ThreadPoolExecutor的shutdown方法后,处于shutdown状态;
调用shutdownNow方法后,处于stop状态 所有工作线程已经销毁并且缓存队列清空,处于terminated状态任务提交发生了什么
通过ThreadPoolExecutor.execute()方法提交任务,
如果线程数小于核心线程数,则创建线程执行任务; 否则,如果线程数小于最大线程数,则尝试将任务放进等待队列; 如果等待队列已满,并且线程数小于最大线程数,则新建线程执行该任务; 如果已达最大线程数,则采取拒绝策略。关于keepAliveTime,当核心池已满时,会对核心池线程的空闲时间进行判断并回收,直至线程数不大于核心线程数。
如果还设置了allowCoreThreadTimeOut,那么在线程数小于等于核心线程数的时候也会回收等待队列的类型
- ArrayBlockingQueue,必须指定大小- LinkedBlockingQueue,默认大小为最大- SynchronousQueue,新建线程执行任务
拒绝策略
- ThreadPoolExecutor.AbortPolicy:丢弃任务,抛出RejectedExecutionException异常- ThreadPoolExecutor.DiscardPolicy:丢弃任务,不抛出异常- ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前端的任务- ThreadPoolExecutor.CallerRunsPolicy:调用者处理该任务
线程池的关闭
- shutdown():不再接受新任务,等待已有任务完成- shutdownNow():不再接受新任务,尝试中断正在执行的任务并清空等待队列(通过调用每个线程的interrupt方法)
合理配置线程池大小
- cpu密集型:cpu+1- IO密集型:2*cpu
线程池使用示例
public class ThreadTest { public static void main(String[] args) { ThreadPoolExecutor executor=new ThreadPoolExecutor( 1000,2000,1000, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(1000)); for(int i=0;i<999;i++){ MyTask myTask = new MyTask(i); executor.execute(myTask); System.out.println("核心池线程数: "+executor.getCorePoolSize() +"等待队列: "+executor.getQueue().size() +"已完成任务数"+executor.getCompletedTaskCount()); } executor.shutdown(); } }class MyTask implements Runnable{ private int taskNum; public MyTask(int taskNum) { this.taskNum = taskNum; } @Override public void run() { System.out.println("开始task "+taskNum); try { Thread.currentThread().sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("结束task "+taskNum); }}
参考:https://www.cnblogs.com/exe19/p/5359885.html