在任务与执行策略之间的隐性耦合

news/2024/11/27 2:43:57/

我们已经知道, Executor 框架可以将任务的提交与任务的执行策略解耦开来。就像许多对复杂过程的解耦操作那样,这种论断多少有些言过其实了。虽然Executor 框架为制定和修改执行策略都提供了相当大的灵活性,但并非所有的任务都能适用所有的执行策略。有些类型的任务需要明确地指定执行策略,包括:

依赖性任务。大多数行为正确的任务都是独立的:它们不依赖于其他任务的执行时序、执行结果或其他效果。当在线程池中执行独立的任务时,可以随意地改变线程池的大小和配置,这些修改只会对执行性能产生影响。然而,如果提交给线程池的任务需要依赖其他的任务,那么就隐含地给执行策略带来了约束,此时必须小心地维持这些执行策略以避免产生活跃性问题

使用线程封闭机制的任务。与线程池相比,单线程的Executor 能够对并发性做出更强的承诺。它们能确保任务不会并发地执行,使你能够放宽代码对线程安全的要求。对象可以封闭在任务线程中,使得在该线程中执行的任务在访问该对象时不需要同步,即使这些资源不是线程安全的也没有问题。这种情形将在任务与执行策略之间形成隐式的耦合——任务要求其执行所在的Executor 是单线程的。如果将Executor从单线程环境改为线程池环境,那么将会失去线程安全性。

对响应时间敏感的任务。GUI应用程序对于响应时间是敏感的:如果用户在点击按钮后需要很长延迟才能得到可见的反馈,那么他们会感到不满。如果将一个运行时间较长的任务提交到单线程的Executor中,或者将多个运行时间较长的任务提交到一个只包含少量线程的线程池中,那么将降低由该Executor管理的服务的响应性。

                  

这个要求并不需要这么严格,只要确保任务不会并发执行,并提供足够的同步机制,使得一个任务对内存的作用对于下一个任务一定是可见的——这正是newSingleThreadExecutor 提供的保证。

使用ThreadLocal 的任务。ThreadLocal使每个线程都可以拥有某个变量的一个私有“版本”。然而,只要条件允许, Executor可以自由地重用这些线程。在标准的Executor 实现中,当执行需求较低时将回收空闲线程,而当需求增加时将添加新的线程,并且如果从任务中抛出了一个未检查异常,那么将用一个新的工作者线程来替代抛出异常的线程。只有当线程本地值的生命周期受限于任务的生命周期时,在线程池的线程中使用ThreadLocal才有意义,而在线程池的线程中不应该使用ThreadLocal在任务之间传递值。

只有当任务都是同类型的并且相互独立时,线程池的性能才能达到最佳。如果将运行时间较长的与运行时间较短的任务混合在一起,那么除非线程池很大,否则将可能造成“拥塞”。如果提交的任务依赖于其他任务,那么除非线程池无限大,否则将可能造成死锁。幸运的是,在基于网络的典型服务器应用程序中——网页服务器、邮件服务器以及文件服务器等,它们的请求通常都是同类型的并且相互独立的。

在一些任务中,需要拥有或排除某种特定的执行策略。如果某些任务依赖于其他的任务,那么会要求线程池足够大,从而确保它们依赖任务不会被放入等待队列中或被拒绝,而采用线程封闭机制的任务需要串行执行。通过将这些需求写入文档,将来的代码维护人员就不会由于使用了某种不合适的执行策略而破坏安全性或活跃性。

  线程饥饿死锁

在线程池中,如果任务依赖于其他任务,那么可能产生死锁。在单线程的Executor中,如果一个任务将另一个任务提交到同一个Executor,并且等待这个被提交任务的结果,那么通常会引发死锁。第二个任务停留在工作队列中,并等待第一个任务完成,而第一个任务又无法完成,因为它在等待第二个任务的完成。在更大的线程池中,如果所有正在执行任务的线程都由于等待其他仍处于工作队列中的任务而阻塞,那么会发生同样的问题。这种现象被称为线程饥饿死锁(Thread Starvation Deadlock),只要线程池中的任务需要无限期地等待一些必须由池中其他任务才能提供的资源或条件,例如某个任务等待另一个任务的返回值或执行结果,那么除非线程池足够大,否则将发生线程饥饿死锁。

在程序清单8-1的ThreadDeadlock中给出了线程饥饿死锁的示例。RenderPageTask向Executor 提交了两个任务来获取网页的页眉和页脚,绘制页面,等待获取页眉和页脚任务的结果,然后将页眉、页面主体和页脚组合起来并形成最终的页面。如果使用单线程的Executor,那么ThreadDeadlock 会经常发生死锁。同样,如果线程池不够大,那么当多个任务通过栅栏(Barrier)机制来彼此协调时,将导致线程饥饿死锁。

Future<String>header, footer;

header =exec. submit(new LoadFileTask("header. html"));

footer =exec. submit(new LoadFileTask("footer. html"));

String page =renderBody();

//将发生死锁——由于任务在等待子任务的结果

return header. get()+page +footer. get();

每当提交了一个有依赖性的Executor任务时,要清楚地知道可能会出现线程“饥饿”死锁,因此需要在代码或配置Executor 的配置文件中记录线程池的大小限制或配置限制。

除了在线程池大小上的显式限制外,还可能由于其他资源上的约束而存在一些隐式限制。如果应用程序使用一个包含10个连接的JDBC连接池,并且每个任务需要一个数据库连接,那么线程池就好像只有10个线程,因为当超过10个任务时,新的任务需要等待其他任务释放连接。

  运行时间较长的任务

如果任务阻塞的时间过长,那么即使不出现死锁,线程池的响应性也会变得糟糕。执行时间较长的任务不仅会造成线程池堵塞,甚至还会增加执行时间较短任务的服务时间。如果线程池中线程的数量远小于在稳定状态下执行时间较长任务的数量,那么到最后可能所有的线程都会运行这些执行时间较长的任务,从而影响整体的响应性。

有一项技术可以缓解执行时间较长任务造成的影响,即限定任务等待资源的时间,而不要无限制地等待。在平台类库的大多数可阻塞方法中,都同时定义了限时版本和无限时版本,例如Thread. join、BlockingQueue. put、CountDownLatch. await以及Selector. select等。如果等待超时,那么可以把任务标识为失败,然后中止任务或者将任务重新放回队列以便随后执行。这样,无论任务的最终结果是否成功,这种办法都能确保任务总能继续执行下去,并将线程释放出来以执行一些能更快完成的任务。如果在线程池中总是充满了被阻塞的任务,那么也可能表明线程池的规模过小。


http://www.ppmy.cn/news/204600.html

相关文章

2023年全球项目管理系统排行榜:推荐15家值得关注的项目管理系统

在当今世界&#xff0c;管理项目已经成为许多企业不可分割的一部分。因此&#xff0c;拥有正确的项目管理系统对于确保任何业务的成功都是至关重要的。随着技术的不断发展&#xff0c;好用的项目管理系统也在不断发展&#xff0c;以满足现代工作场所日益增长的需求。到2023年&a…

5G+IoT时代 从柔宇FlexPai 2看智能手机的未来

未来的手机会是什么样子&#xff1f;是智能穿戴形态&#xff0c;VR、AR&#xff0c;还是马斯克的脑机接口&#xff1f;又或是这两年十分火热的可折叠智能手机&#xff1f; 9月22日&#xff0c;柔宇科技发布了新一代折叠屏手机FlexPai 2&#xff0c;向人们展示了其对未来智能设…

重磅!5G手机密集发布, vivo NEX 3有何看点

中国软件网 报道 | 公众号&#xff1a;Hapiweb-soft6 201 9年 第三季度接近尾声&#xff0c;手机厂商们的5G新品手机&#xff0c;已经进入发布的“高峰期”。 2019年9月16日&#xff0c;vivo举行了NEX 3新品发布会。发布会上&#xff0c;vivo NEX系列产品高级总监洪沂历数了NEX…

android 护眼模式设置参数,节能护眼看这里!玩转Android手机的显示设置

原标题&#xff1a;节能护眼看这里&#xff01;玩转Android手机的显示设置 对智能手机而言&#xff0c;除了性能以外&#xff0c;其屏幕的显示效果和续航时间对体验的影响往往更加直观。在系统设置的“显示”功能列表中&#xff0c;我们就能最大限度挖掘屏幕的显示质量&#xf…

定了!华为生产不含美国芯片的手机!

整理 | Elle 背景 2019年5月&#xff0c;美国商务部正式把华为列入了“实体清单”&#xff0c;即禁止美企向华为出售相关技术和产品除非获得政府许可&#xff0c;此通告一出&#xff0c;大家纷纷担忧接下来的华为该如何应对此问题。 自此&#xff0c;美国持续将华为技术设备视为…

荣耀宣布面向全球发布荣耀Magic3系列手机

深圳2021年8月16日 /美通社/ -- 全球科技品牌荣耀发布了全新荣耀Magic3系列手机&#xff0c;这是标志性旗舰智能手机系列&#xff0c;兼具高端技术和尖端设计。荣耀Magic3系列是荣耀自品牌独立以来推出的第一个旗舰产品系列&#xff0c;包括荣耀Magic3、荣耀Magic3 Pro和荣耀Ma…

入手Hi nova9 Pro一周,你们关心的问题都在这里

12 月初&#xff0c;中国邮电器材集团有限公司召开了发布会&#xff0c;正式发布了全新的独立手机品牌——Hi nova系列&#xff0c;以及两款新品Hi nova9 Pro和Hi nova9。其面向当下追求时尚潮流、渴望更好地记录自己的不凡生活、希望表达自己独特观点的年轻人推出&#xff0c;…

机器学习常识 19: 矩阵分解

摘要: 矩阵分解是使用数学应对机器学习问题的一类典型而巧妙的方法. 1. 基本概念 矩阵分解是把将一个 m n m \times n mn 矩阵 A \mathbf{A} A 分解为 m k m \times k mk 矩阵 B \mathbf{B} B 和 n k n \times k nk 矩阵 C \mathbf{C} C, 使得 A ≈ B C T \mathbf{…