1.为什么要用线程池?线程池有哪些好处?=线程被一直维护着有什么好处?
2.让线程池执行任务需要实现哪些接口?它们有什么区别?最好用什么方式来创建线程池?
3.线程池执行任务的方法有哪些?有什么区别?=线程池中execute()和submit()方法有什么区别?
4.应该怎么创建线程池?说说TheadPollExecutor构造方法的参数都是什么意思?以及它的拒绝任务策略(饱和策略)(handler参数的实现)?
5.说说线程池的整个流程?
1.
Q:为什么要用线程池?线程池有哪些好处?=线程被一直维护着有什么好处?
A:
1.不用来回频繁地创建和销毁线程。降低资源消耗。
2.任务到达的时候就可以直接开始执行,而不用等待线程创建的过程。提高响应速度。
3.为线程进行统一地进行分配,调优和监控。更好地管理线程。
2.
Q:让线程池执行任务需要实现哪些接口?它们有什么区别?最好用什么方式来创建线程池?
A:
让线程池执行任务需要实现Runnable接口或Callable接口,它们的区别在于实现Runnable接口不能返回结果,返回值为void。而实现Callable接口可以返回结果或抛出异常,返回值自己定义。(看Runnable接口和Callable接口的源码)
最好用ThreadPoolExecutor来创建线程池,而不用其它的来创建。
(
1.用ThreadPoolExecutor构造方法创建
2.用Executors静态类的newXXX方法(底层调用了ThreadPoolExecutor的构造方法)
)
3.
Q:线程池执行任务的方法有哪些?有什么区别?=线程池中execute()和submit()方法有什么区别?
A:
execute()和submit()是线程池执行任务的方法。
execute()方法返回值为void,不知道是否任务是否被线程池执行成功
而submit()方法返回一个Future对象,通过future对象可以判断是否执行成功,future里有个isDone()方法返回值为boolean,可以看到任务是否执行成功。还可以调用furture的get方法来得到计算结果,get方法会阻塞当前进程。
execute()和submit()是线程池执行任务的方法,是看任务执行结果的,而Runnable和Callable接口是线程执行任务需要的实现的接口。(前提条件)
4.
Q:应该怎么创建线程池?说说TheadPollExecutor构造方法的参数都是什么意思?以及它的饱和策略(handler参数的实现)?
A:
1.用ThreadPoolExecutor构造方法创建
2.用Executors静态类的newFixedThreadPool,newSingleThreadExecutor,newCachedThreadPool方法来创建,它们调用了ThreadPoolExecutor的构造方法
全部通过ThreadPoolExecutor构造的方式来创建。其它方式可能会造成OOM的风险,out of memory内存溢出的风险。
newFixedThreadPool:创建的是一个线程数量固定的线程池。
newSingleThreadExecutor:创建的是一个只有一个线程的线程池。
newCachedThreadPool:创建一个线程数量根据实际情况变化的线程池。
共同点:当任务来的时候如果没有空闲线程,都是把任务放到队列中,等到有空闲线程的时候才去执行。
不同点:newCachedThreadPool优先复用空闲的线程,当所有线程都在工作时来了任务,则会创建新的线程。
ThreadLocalExecutor的构造方法重要参数有corePoolSize,maximumPoolSize,workQueue。(核心线程数,最大线程数,任务队列)还有常见参数keepAliveTime,unit,threadFactory,handler。(当线程数大于任务数后空闲线程的存活时间,unit是存活时间的单位,创建thread的工厂,还有饱和策略handler)
1.corePoolSize:核心线程数,同一时刻最多能有多少个线程一起在工作。因为一个核心有多个线程,但是同一时刻一个核心只能有一个线程在运行。
2.maximumPoolSize:最大线程数。
什么是ThreadLocalExecutor的拒绝任务策略(饱和策略)?
拒绝任务策略:就是当任务已经堆满了队列,线程也达到了最大线程数,此时还有新任务到来了,该如何处理的策略。
有4个策略:AbortPolicy,CallerRunsPolicy,DiscardPolicy,DiscardOldestPolicy
abort是流产,终止的意思。AbortPolicy是终止策略,再遇到任务会直接抛出异常。CallerRunsPolicy是让调用者线程自己去处理这个任务,所以处理的时间会被延长。但是所有的任务都不会丢失。
DiscardPolicy是丢弃新来的任务,实现的话就什么都不做,就表明丢弃了。DiscardOldestPolicy是丢弃队列中最长时间没有处理的任务,然后把新任务加入队列。
这4个策略分别是4个ThreadPoolExecutor的静态内部类。可以去查看源码。
5.
说说线程池的整个流程?
1.线程池刚被创建出来里面有0个线程,当任务过来时才去创建线程(当然可以提前把corePoolSize个线程创建出来)。
2.当线程池中线程的数量小于corePoolSize时,来一个任务创建一个线程去执行。
3.当线程池中线程的数量大于corePoolSize且工作队列没满时,则把任务暂存在workQueue工作队列中。等线程执行完其它任务从工作队列取出任务执行。
4.当线程池中线程的数量大于corePoolSize且工作队列满了,但小于maximumPoolSize。任务来的时候就直接创建线程去执行该任务。
5.当线程池中线程的数量大于corePoolSize且工作队列满了,但等于maximumPoolSize。则进行拒绝任务策略(abortPolicy终止策略,抛出异常;CallerRunsPolicy当前线程执行该任务,推迟执行效率变慢;DiscardPolicy丢弃策略,什么都不干;DiscardOldestPolicy丢弃在队列里停留时间最长的任务,并执行该任务)