1.线程池的几个重要的参数?
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler)
corePoolSize:线程池核心线程数
maximumPoolSize:线程池最大线程数
keepAliverTime:当活跃线程数大于核心线程数时,空闲的多余线程最大存活时间
unit:存活时间的单位
workQueue:存放任务的阻塞队列
threadFactory:线程工厂,主要用来创建线程;
handler:超出线程范围和队列容量的任务的处理程序(表示拒绝处理任务时的策略)
当阻塞队列满了,且没有空闲的工作线程,如果继续提交任务,必须采取一种策略处理该任务,线程池提供了4种策略:
- 丢弃任务并抛出异常
- 也是丢弃任务,但是不抛出异常
- 丢弃队列最前面的任务,然后重新尝试执行该任务(重复该过程)
- 由调用线程执行该任务
2.线程池的作用?
答:1.对线程进行了统一的管理,因为线程本身是不可预期的,
2.线程池的底层并不是new一个线程,然后调用start()方法,而是有一个名字叫worker的线程,它首先要持有runnable的对象的引用,然后在它的run方法里面直接调用这个对象的run方法。 Worker线程不一定会因为你的runnable跑完而被销毁,会接着去跑别的线程,实现了线程的复用。
3.向线程池提交任务有两种是实现方式?
答: 1)Executor.execute(Runnable command);
2) ExecutorService.submit(Callable<T> task);
4.ThreadPoolExecutor的核心方法execute()的执行流程:
答:1)首先通过wordCountOf()获知当前线程池中的线程数,
如果小于核心线程数corePoolSize,就通过addWorder()创建线程执行该任务;
否则,将该任务放入阻塞队列。
2)如果能成功放入阻塞队列中,
如果当前线程池是非RUNNING状态,则将该任务从阻塞队列中移除,然后执行reject()方法处理该任务;
如果当前线程池是RUNNING状态,则需要再次检查当前线程池,是否有空闲的线程,如果有则执行该任务;
3)如果不能将该任务放入阻塞队列,说明阻塞队列已满;那么将通过addWorder()方法尝试创建一个新的线程去执行这个任务;如果addWork()执行失败,说明线程池中线程数达到了最大线程数maxPoolSize,则执行reject() 方法处理任务。
5.submit()的内部实现?
答:会将提交的Callable任务封装成一个FutureTask对象,FutureTask类实现了Runnable接口,这样就可以通过Excutor.execute()提交FutureTask到线程池中等待被执行,最终执行的是FutureTask的run方法。
6.execute和submit()的比较:
答:两个方法都可以向线程池提交任务,execute()方法的返回类型是void,它定义在Executor接口中,而submit()方法可以返回持有计算结果的Future对象,它定义在ExecutorService接口中,扩展了Executor接口。
7.线程池的总结:
答:线程池的核心线程数,当提交一个任务时,线程池会创建一个新的线程执行该任务,直到当前线程池中的线程数等于核心线程数corePoolSize;如果当前线程池的线程数为核心线程数,继续提交任务则会被保存到阻塞队列中,等待被执行;如果阻塞队列满了,会创建新的线程执行该任务,直到线程池中的线程数达到线程池的最大线程数maxPoo lSize,这时如果继续提交任务,则只能执行reject()方法处理该任务。