NO.68 结束即开始:Fork/Join并发框架

关注本公众号,一天一个知识点,持续精进!

碎片时间|体系学习

今天是

2018年的第70

这是代码荣耀的第121篇原创

00、引言

优秀框架的精要在于是一种最佳的工程实践,可复用、性能好、代码质量优、提升了框架使用者的思考层次....都是其优点。Fork/Join框架就是这样的一种并发框架,通过该框架,软件开发人员能够非常方便地从传统的串行编程过度到并发编程,简单到利用一种编程模式并结合几个API接口进行编码,就能充分发挥当前多核硬件平台的计算能力。

使用Fork/Join框架,开发人员只需要去关注任务划分的策略和合并子任务结果的方式,其他的繁重任务就交给框架吧!

可见,该框架没有做到对软件开发人员完全透明,但是已经极大的简化了编写并发程序的很多琐碎工作。对于符合Fork/Join模式的业务应用,软件开发人员不再需要处理多线程同步、数据共享等底层编程,也不会出现死锁、线程不安全等令人脑细胞锐减的错误,让开发人员更加关注上层业务逻辑的实现,而不是去过多的关注底层实现,提升了开发人员思考问题的层次。

01、注意事项

1. 任务划分

利用框架进行任务划分的时候,面对大容量任务,切记不要把任务划分层次太深;一方面,系统内的线程数量越积越多,导致系统性能急剧下降;另外一方面,函数调用层次会变得很深,最终可能会导致JVM的StackOverflowError错误。

2. 工作窃取算法

ForkJoinPool类实现了ExecutorService接口和工作窃取算法。调用该类的execute方法中,如果传入的是runnable对象,ForkJoinPool类就不采用工作窃取算法,ForkJoinPool类仅在使用ForkJoinTask类时才使用工作窃取算法。

3. 同步与异步运行

在ForkJoinPool中执行ForkJoinTask时,可以采用同步或异步方式。两种不同的运行方式,会出现两种不同的运行表现。

一方面,当采用同步方式执行时,发送任务给Fork/Join线程池的方法直到任务执行完成后才会返回结果;当采用异步方式执行时,发送任务给执行器的方法将立即返回结果,但是任务仍能够继续执行。

另外一方面,当采用同步方式时,调用这些方法(比如invokeAll方法)时,任务被挂起,直到任务被发送到Fork/Join线程池中执行完成。这种方式允许ForkJoinPool类采用工作窃取算法来分配一个新任务给在执行休眠任务的工作线程;与此对比的是,当采用异步方法(比如fork方法)时,任务将继续执行,因此ForkJoinPool类无法使用工作窃取算法来提升应用程序性能,只有调用join或get方法来等待任务的结束时,ForkJoinPool类才可以使用工作窃取算法。

4. 取消任务

ForkJoinTask类提供的cancel方法允许取消一个仍没有被执行的任务,如果任务已经开始执行,那么调用cancel方法也无法取消

具体使用方法如下:

5. 异常处理

ForkJoinTask在执行的时候可能会抛出异常,但是我们没有办法在主线程里直接捕获异常,所以ForkJoinTask提供了isCompletedAbnormally()方法来检查任务是否已经抛出异常或已经被取消了,并且可以通过ForkJoinTask的getException方法获取异常。

getException方法返回Throwable对象,如果任务被取消了则返回CancellationException;如果任务没有完成或者没有抛出异常则返回null。

具体使用方法如下:

02、典型用例——模拟文件爬虫

1

03、典型用例——模拟文件系统关键字检索

2

上述程序的可能运行结果如下:

由于实例一、二的代码里面都有详细的注释,为此不再做过多的说明;如遇问题,欢迎老铁们踊跃留言交流。

04、小结

本文对Fork/Join框架注意事项、使用场景、复杂应用方法进行了说明。本文即是Fork/Join的完结篇;至此,我们把Fork/Join并发框架从基本框架、算法原理、API使用方法、核心源码实现、注意事项、典型应用一一都进行了说明。这是一次完整且难忘的Fork/Join框架探险之旅,欢迎老铁们在留言区写下心得,与大家共同交流。

如果本文对老铁有所启发,

请多转发、转载、打赏、点赞!

  • 发表于:
  • 原文链接:http://kuaibao.qq.com/s/20180310G0V6O000?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券