线程池

来源:互联网 发布:php判断时间前后 编辑:程序博客网 时间:2024/06/05 07:22

任务:抽象的离散的工作单元  有清晰边界,不依赖于其他任务

并发的执行任务以提高吞吐量以及降低响应时间

任务处理过程是从主线程中分离出来的

任务可以并行处理

任务执行代码必须线程安全


线程生命周期的开销很高   活跃的线程资源消耗很大  稳定性:不能无限制创建线程


线程池

好处:降低创建线程的开销,降低响应时间,有效地控制线程资源

任务是一组逻辑工作单元,而线程则是任务异步执行的机制

Executor接口是基础框架,提供了execute(Runnable)方法。 -- 提供任务给框架,框架执行任务,实现了解耦。 线程由框架来提供

Executors是一个辅助类,其中有很多工厂方法可以创建线程池:

newFixedThreadPool:每提交一个任务创建一个线程,当达到规模后不再变化

newCachedThreadPool:可以根据提交的任务状态当前状态创建和回收线程

newSingleThreadExecutor    : 单线程执行任务,一个线程结束会用另一个线程代替  任务按照顺序执行,顺序有策略决定

newScheduledThreadPool : 固定长度的线程池,以延迟或者定时的方式来执行。


ExecutorService 扩展了 Executor接口,添加了管理生命周期的方法   三种状态:运行,关闭,中止  (线程池的状态) 通过shutdown,shutdownnow等来管理


用callable代替runnable: 返回一个Future对象  ,他表示一个任务的生命周期   

每个任务分为创建,提交,开始和完成四个状态。 提交未执行可以取消,正在执行只有响应中断才能取消,执行完成的无法取消

Future提供了一系列get,cancel等方法来获取任务状态以及取消任务等


线程池的缺点:

1.不应该使用threadlocal  

2.线程池中的任务只有是同类型,且互相独立才能达到很好的效果  如果将耗时很长和很短的任务混在一起,会造成堵塞,  任务相互依赖还有可能产生死锁


死锁:单线程中一个任务将另一个任务提交,并且等待这个任务的结果,会死锁   同样的情况会发生在线程池中,多个任务出现上述情况   称为线程饥饿死锁

出现上述死锁的主要原因是:1.任务之间的依赖  2.线程池容量有限

时长:如果线程池不够大,且有大量耗时很长的任务,最终线程池会被这种任务填满,导致后续提交的耗时较短的任务响应时间变长(解决方案:设置超时)


ThreadPoolExecutor

  继承AbstractExecutorService

     实现 ExecutorService

public ThreadPoolExecutor(int corePoolSize, int maxmumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,RejectExecutionHandler handler){...}

corePoolSize:基本大小(没有任务时的线程池大小),maxmumPoolSize(最大线程池大小,即任务数量超过基本大小后能增加到最大的数量)

keepAliveTime:超时时间,空闲时间超过该值的线程会被标记可回收,当线程数超过基本大小后,这些线程会被回收


线程池用一个Executor管理的Rnnuable队列储存待处理的任务,一个等待的任务由一个Runnable和一个链表节点表示

workQueue就是这个队列。可以选择无界队列(无界LinkedBlockingQueue),有界队列(有界LinkedBlockingQueue,ArrayBlockingQueue)和同步移交(SynchronousQueue)

排队的策略跟workQueue的类型相关,如LinkedBlockingQueue和ArrayBlockingQueue采用FIFO,还可以使用PriorityBlockingQueue来排序

同步移交

如果任务之间相互依赖,应该采用无界的池和队列

饱和策略:当队列被填满后,根据这个策略来决定如何处理任务。 如:丢弃当前任务,丢弃下一个将要执行的任务,抛出一个异常等

ThreadFactory是一个接口,其中有一个方法Thread newThread(Runnable r)用来创建线程。可以自己实现这个接口定义想要实现现成的方式

ThreadPoolExecutor还提供了几个可以在子类中覆盖的方法beforeExecute,afterExecute和terminated,重写这些方法可以扩展该类的行为



自己实现一个线程池:http://blog.csdn.net/zq602316498/article/details/41819489

主要思想:定义一个线程池类, 在定义一个Thread的子类  

                  线程池主要属性有储存线程的List, 关闭线程池的标志位,线程数量,  

                  主要方法有:添加线程到list,关闭线程池(关闭所有线程,清空list,设置标志位),执行一个任务

                  执行任务方法:如果线程池没有关闭,则从list中获取一个线程,为线程添加runnable任务,并执行


               Thread子类: 属性主要有持有该线程的线程池类   线程关闭标志位   Runnable(用来设置任务)

                                      主要方法:构造方法   run方法   设置runnable的方法   关闭方法

                

               线程池如何管理线程:

                          线程池持有线程的一个容器。每次需要新的线程执行任务,则会从容器中提取一个线程,并设置任务,再调用执行方法

                           线程执行过后,自动被添加回线程池的容器中,并挂起(wait方法),等待下一次调用

                          线程池持有的线程从添加进来的一刻起就处于start状态,只不过不执行任务时,处于挂起  (总的来说就是在线程池中的线程都处于挂起状态)

                           执行调用方法其实就是给线程类set一个新的runnable,然后notifyall()方法唤醒他,让他执行任务,执行完毕后在回到挂起状态

                                       

    关于线程的管理:

   线程自己不能设置关闭,需要通过其他线程协同处理。例如,在一个执行任务中设置cancel标志位,在执行方法run中根据标志位来结束run方法

 利用中断来停止任务:阻塞方法在被interrupt后,会抛出interruptexception异常,可以interrupt方法通知中断一个线程,该线程可以通过捕获异常,或者自己主动显示调用interrupt状态来判断收到中断请求后的操作。以此来关闭任务

通过Future来取消线程池中的任务


持有线程的服务如果生命周期大于持有线程的生命周期,他就应该提供生命周期管理方法,例如ExecutorService应该提供管理线程的生命周期方法

处理非正常线程的中止:1.对线程的非检查异常进行主动处理  2.未捕获的异常会导致线程中止,可以自己实现UncaugntExceptionHandler来处理。线程池中的ThreadFactory就会调用UncaugntExceptionHandler来处理线程




原创粉丝点击