多线程(四)--线程池的原理的基本理解
一、线程池简介:
1.线程池的出现,在多线程中当我们需要创建一个线程时,需要作出创建T1,执行T2,销毁T3总共三个阶段。而正常情况下,创建一个线程到销毁需要消耗1MB左右的大小,当我们只是创建几个线程时,这点消耗不足为道,但是我们需要执行大量的任务时,我们就需要创建大量的线程。我们花费在T1与T3上面的资源过高,会导致内存资源的无辜消耗,此时线程池的出现解决了这个问题。
2.线程池的原理:当我们需要完成1000个任务时,我们需要创建1000个线程,T2*1000的消耗不可避免,但是T1与T3的消耗却也要1000倍。而线程池的设计原理,就是需要完成1000个任务时,我们同时创建10个线程放置于线程池内,并且将1000个任务放置于工作区。同时将10个工作作用于10个线程,当任务完成时,线程并不会销毁,而是将线程的引用赋给新的任务继续执行。这样我们消耗了T2*1000+(T1+T3)*10,而不是(T1+T2+T3)*1000。当然这些消耗是一种理想中的消耗,在使用过程中依然会造成一些其他的消耗,但是总体来说线程池的使用会大大降低大量线程任务时对系统资源的消耗。
3.线程池(ThreadPool)实现了AbstractExecutorService接口,而AbstractExecuptorService接入了ExecutorService,而ExecutorService则接入了Executor接口。
二、Executor介绍
1.Executor:仅仅只有Excutor()这个抽象方法。
2.ExecutorService接入Executor(),并且假如了shutdown(),isShutdown(),submit(),invokeAll(),invokeAny()等方法,都加入中断异常处理。
3.AbstractExecutorService:一个实现了ExcutorService接口的抽象类,并没有剩余抽象方法,至于设置抽象类的原因,应该是不允许实例化。
4.AbstractExecutorService内的方法:
invokeAll:执行给定的任务S,返回这些任务的直接结果以及期货列表;可重载加入时间限制。
invokeAny执行给定的人为奴,返回一个执行结果以及期货列表;可重载加入时间限制。
submit:提交一个可执行的任务,并且返回该任务的未来
newTaskFuture:返回一个可执行任务的RunableFuture
三、使用线程池的风险
1.死锁
死锁指,当一组线程都在等待该组线程中另一个线程的执行结果时(该线程因为阻塞等原因无法得到结果)。最常见的就是两个线程各持有一个资源,且都在等在对方资源。
但是线程池会有另外的风险,当所有运行的线程都在等待另一个等待队列的任务的执行结果时,但是该任务却因为其他线程无法完成执行导致该任务无法运行时。会造成死锁。
2.资源不足
线程池的建立与使用就是为了解决多线程的资源消耗问题,当然线程池的确可以解决线程资源问题,但需要的是对线程池大小作出合适的调整。
线程池中,每个线程除开本身的资源消耗外,还需要创建两个任务堆栈,用于存放任务列表。所以过多无意义的线程的创建对于系统资源来说是一种极大的损耗。不合理的太过大的线程池,会导致资源不足的情况,当然过于小的线程池也会导致效率过低,所以线程池大小的设置对于线程池来说是极为重要的。
3.并发错误
线程池以来与wait()与notify()方法调用,这两种方法难于使用,容易引发并发错误。
4.线程泄漏
这对于线程池来说是一个最为常见严重的错误,当线程执行任务时,会有可能发出RunTimeException或者错误时,如果池类没有捕捉到该异常或错误,就会导致该线程彻底失去,累计过多时,会导致线程池中线程为空,任务无法继续执行。
5.请求过载
当任务排在队列中时,也会产生大量的系统资源消耗,过多的请求排在队列,可能导致请求过载,可以设置暂时很忙无法响应来结局该异常。
四、线程池中的设置
1.(int)PoolSize:代表线程池中目前线程的数目。当生成新的线程时,需要+1处理;
2.(long)KeepAliveTime:代表线程闲置多少时间会自动终止线程,需要在设置;
3.(TimeUnit)Unit:用于设置时间数的单位(year,mouth,day,hour,minutes,seconds,milliseconds,microseconds,nanoseconds)
4.(int)corePoolSize:核心线程的数目,线程池建立时,默认没有线程运行,当任务来临时,则启用对象,当线程数目达到核心线程数目时,则将新来的任务放置于任务队列中。可用prestartCoreThread或则prestartAllCoreThread在没有任务的情况下创建线程,当然没有任务时,经过KeepAliveTime后会自动死亡。将线程池比作一个公司时,可以将核心线程比作核心员工,而其他线程则可以比作临时员工,核心员工可以永远在,而临时员工在不需要时就被销毁。
5.threadFactory:线程工厂,用于创建线程。
6.workQueue:任务队列,如果数据结构中的队列,任务队列满足先进先出原则。当所有线程都有在执行时,会将多余的任务放入线程队列中等待调用。
7.handler:当拒绝任务加入是会产生的策略。
8.maxmumPoolSize:最大线程池数量,当线程数目到达该数目时,则不会在创建线程。