并发编程第二部分结构化并发应用程序

看一看这个玩意:
在这里插入图片描述

  • poll -->【若队列为空,返回null】

  • remove >【若队列为空,抛出NoSuchElementException异常】

  • take -->【若队列为空,发生阻塞,等待有元素】
    在这里插入图片描述
    以上代码串行执行,但是handleRequest执行很慢,可用以下方案啊,每次请求都创建一个线程,结构上类似於单线程版本,但是每次accept的时候都可以交给线程去处理,然后接受下一个连接
    在这里插入图片描述
    由此我们可以得出小结论

  • 任务处理过程从主线程分离出来 ,主循环能更快等到下一个到来的连接,这样程序完成前面请求后接受新请求,提高响应性

  • 任务并行处理,服务多个请求,例如等待i/o,获取锁,获取资源可用性,提高程序吞吐量

  • 任务处理必须保证线程安全

接下来讲到基于生产者——消费者模式的框架Exexutor,生产者提交任务,消费者执行任务
在这里插入图片描述
创建一个线程池,固定长度线程池可以容纳100个线程
在这里插入图片描述
为每一个请求创建线程
在这里插入图片描述
也可以编写一个单线程执行任务同步执行并返回
在这里插入图片描述

线程池
Executor类库提供了几个工厂方法

  • newFixedThreadPool :创建固定长度线程池,提交一个任务创建一个线程,直到最大,如果发生Exception结束了,会创建一个新的线程
  • newCachedThreadPool:创建可缓存线程池,如果池当前规模超过处理需求,回收空闲线程,需求增加,增加新线程
  • newSingleThreadExecutor:单线程Executor,创建的单线程如果Exception结束,会创建另一个线程来代替。确保串行
  • newScheduledThreadPool:创建固定长度线程池,以延迟定时方式执行
  • newFixedThreadPool
  • TaskExecutionWebServer:web使用Executor用execute将任务提交到工作队列,工作线程反复从队列取出任务并执行。

线程池由为每任务分配一个线程百年城基于线程池策略,web服务器不会在高负债情况下失败,可实现调优、管理、监视、记录日志、报错、so on。。。。。。如果不正确关闭Executor JVM无法结束

Executor生命周期管理方法,调用shutdown即可
在这里插入图片描述
延迟与周期任务
可以用ScheduledThreadPoolExecutor

future 任务生命周期只进不退
get()方法取决于任务状态 未开始?运行?已完成?如果已完成,任务抛出Exception,未完成get将阻塞到完成
在这里插入图片描述
Callable和Future表示这些协同任务的交互,创建Callable下载所有图像,提交到ExecutorService,返回Future描述任务的执行情况。主任务需要的时候会等待future.get执行结果,幸运的话,已经下载好了,或者已经提前在下载中了。
在这里插入图片描述
异常包括两一个是中断,一个是遇到一个Exception。

创建一个BlockingQueue保存计算结果,计算结束调用done,提交任务,先包装成QueueingFuture,改写done方法,访日BlockingQueue
在这里插入图片描述

使用CompletionService实现页面渲染器,每个图像下载都创建独立任务,线程池执行,串行转并行
在这里插入图片描述
多个任务提交到ExecutorService获取结果 InvokeAll方法的参数为一组,返回一组future,执行完毕,中断,超时,InvokeAll将返回。超时后,未完成的被取消
在这里插入图片描述
在这里插入图片描述
下面代码用了素数生成器
。,执行1s后取消,现实中银行用此策略停止支付

在这里插入图片描述

如果生产者速度超越消费者,那么put一直被阻塞,通过中断来取消
在这里插入图片描述
线程在阻塞或者进行重要的工作前检查中断状态
在这里插入图片描述
启动线程,timedRun执行join方法,检查任务中是否有异常抛出,在调用timedRun线程中再次抛出一场,由于throwAble在两个线程共享,所以被声明为volatile
在这里插入图片描述
将任务交给ExecutorService,通过future.get来获取结果,如果抛出一场,则通过future取消
在这里插入图片描述
同步读取套接字,传给processBuffer
在这里插入图片描述

在这里插入图片描述
以下多生产者单消费者,调用log是生产者, LoggerThread相当于消费者,如果消费者的处理速度低于生产者生成速度,BolckingQueue将阻塞生产者,直到日志线程有能力处理新的日志消息。直到日志线程有能力处理日志消息。
在这里插入图片描述
但还有一个终止日志线程的方法,避免jvm无法正常关闭,如果用take响应中断,会丢失等待被写入日志的消息。其他线程在调用log也被阻塞,因为log的消息队列是满的,需要同时取消圣生产者消费者,可以用计数器来控制

在这里插入图片描述

关闭iExecutorService,用shutdown正常关闭速度慢,等到任务执行结束后关闭,用shutdownNow强行关闭速度快,风险更大,未执行就关闭。可以托管给ExecutorService管理
在这里插入图片描述

另一种关闭生产者消费者方式是用"毒丸对象",当得到这个对象,立即停止,提交毒丸之前,所有工作都会被处理,生产者提交读完后将不会提交任何工作
在这里插入图片描述
在这里插入图片描述
仅当生产消费者都一直的情况下才可以用毒丸对象,每个生产者向队列中放1毒丸,消费者接收到N个毒丸才停止

只执行一次的服务,当所有任务都处理完成后才返回,可以通过私有Executor简化服务生命周期管理,Executor生命周期由此方法控制
如下代码checkMail在多台主机上并行检查新邮件,创建Executor,向每台主机提交任务,任务执行完关闭Executor
在这里插入图片描述
应该找出哪些任务已经开始但没有正常完成getCancelledTasks返回被取消的任务清单。
在这里插入图片描述
如图当爬虫关闭的时候,希望保持状态以便重启的时候继续,getPage将记录未开始或被取消的任务,重启就可以把抓取任务加入任务队列
在这里插入图片描述

jvm可以正常关闭也可以强行关闭,最后一个正常线程结束,或者调用了System.exit。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章