任务
任务执行:
任务通常是一些抽象而离散的工作单元,通过把应用程序的工作分解到多个任务中,可以简化程序的组织结构,提供一种自然的事务边界来优化错误恢复过程,以及提供一个自然的并行结构来提升并发性。
如何设计:
找出清晰的任务边界,各个任务之间相互独立,不依赖于其他任务的状态,结果或边界效应。
自然的任务边界选择方式:
以独立的客户请求为边界。
项目中每次客户发起的一次请求,如提交订单,添加购物车,执行的业务都是一个任务,彼此任务之间都是独立的,没有相互依赖的关系。
问题:
既然每次请求进来都是独立的任务,那实际应用中除了像数据库,redis等数据会发生并发的问题外,其他大部分的代码是不是就根本不用考虑并发的问题?因为每个任务中的变量都是每个线程自己独有了,其他线程并不可见,除了更新数据库,redis时需要考虑并发的问题外?
任务的演变过程
串行的执行任务
只有一个线程,请求进来的时候占用,其他的线程阻塞,等待线程空闲
缺点:无法提供高吞吐率或快速响应性。
无限制多线程的执行任务
每个请求进来,都创建一个新的线程来执行任务。
正常状况下,能提升串行执行的性能,只要请求的到达速率不超出服务器的请求处理能力,
如果超出,仍然会有阻塞的情况。
缺点:1.线程生命周期的开销非常高。
2.资源消耗
3.稳定性
有限制多线程的执行任务
线程池Executor框架
异步的任务框架,基于生产者消费者模式
生命周期:创建,提交,开始,完成
优点:
减少了线程创建和销毁的开销
创建线程池的几种方式:
newFixedThreadPool
newCachedThreadPool
newSingleThreadPool
newScheduledThreadPool
项目中有一些任务我们是需要返回结果的,而Executor是一个异步的框架。是没有返回的结果的,这时就需要用到Callable和 Future
只有当大量相互独立且同构的任务可以并发进行处理时,才能体现出将程序的工作负载分配到多个任务中带来的真正性能的提升。
行为良好的软件与勉强运行的软件之间的主要区别:
行为良好的软件能很好的处理失败,关闭和取消等过程
任务取消
取消的原因:
用户请求取消
有时间限制的操作
像dubbo的微服务架构,假设 商城模块正在提交一个订单任务,需要调用商品服务来进行扣减库存的动作,dubbo设置时是有超时时间并有一定的重试次数,现在如果商品服务执行时间超时,虽然超时,但是当前调用的商品服务其实是没有停止的,任务仍然在继续,订单服务会重试3次假设,会不会对商品的库存进行重复扣减?
应用程序事件
错误
关闭
协作的机制:
设置volatile 的已请求取消的标志,任务执行时检查这个标志
private volatile boolean cancelled;
public void run(){
while(!cancelled){
doSomething();
}
}
问题:如果在dosomething时调用一个阻塞方法,那么它将不会检查cancelled标志,永远的执行下去。
中断
理解:它不会真正地中断一个正在运行的线程,而只是发出中断请求,然后由线程在下一个合适的时刻中断自己,(这些时刻也被称为取消点)
中断是实现取消最合理方式
中断策略:
某种形式的线程级取消操作或服务级的取消操作:尽快退出,在必要时进行清理