任务:抽象的离散的工作单元 有清晰边界,不依赖于其他任务
并发的执行任务以提高吞吐量以及降低响应时间
任务处理过程是从主线程中分离出来的
任务可以并行处理
任务执行代码必须线程安全
线程生命周期的开销很高 活跃的线程资源消耗很大 稳定性:不能无限制创建线程
线程池
好处:降低创建线程的开销,降低响应时间,有效地控制线程资源
任务是一组逻辑工作单元,而线程则是任务异步执行的机制
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(最大线程池大小,即任务数量超过基本大小后能增加到最大的数量) 注意:线程数量起始值为0
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来处理线程