RecursiveTask中是否存在对Spring托管bean的锁定



技术堆栈

  • Web应用程序
  • Java 1.7
  • Spring Framework 4

问题

  1. 我需要能够处理应用程序中包含文档的ZIP文件,并递归地解压缩它们。我所说的递归——如果ZIP包含其他ZIP文件,它们也应该被解压缩。然后,所有档案中的所有文件都应该进行处理。

  2. 第1点应并行执行,以加快进程。

实施

  • 我决定使用Java 7中引入的ForkJoinFrame。因此,我最终拥有了Spring管理的单例服务ZipService(具有process(zip(方法(,该服务使用Spring管理的ForkJoinPool来调用ZipPartitionerZipPartitionercompute()方法检查ZIP内容集是否足够小(文档集大小为1(以直接计算,或者是否应继续分区。如果应该直接计算,我会检查当前内容/文件实际上是要处理的文件,还是另一个(嵌套的(ZIP。有趣的是,当我在ZipService中创建ZipPartitioner时,我将this传递给它的构造函数,因此我引用了ZipService。然后,如果在直接计算逻辑中,内容实际上又是一个ZIP,我从ZipService的引用中调用process(ZIP(方法,以便该过程可以递归地重新开始

结果

  • 令人惊讶的是,该实现效果非常好,并将处理持续时间缩短了3倍。然后我决定用JMeter对实现进行基准测试。它在处理5个并发请求时运行良好,但在处理10多个请求时挂起。当ZipPartitioner尝试在ZipService的实例上调用进程(zip(方法时,执行会阻塞。ForkJoinPool中有多少线程并不重要——我检查了1、10、30和1000

问题

  • 我认为这种方法通常有一些错误——将Spring托管bean传递给RecursiveTask,但它处理的请求数量较小。那么,有人能告诉我为什么它会坏,为什么它会起作用吗?你将如何处理这个问题
  • 我怀疑随后对ZipService的请求以某种方式使Spring锁定了它,从而阻止了computeDirect方法的递归调用。你觉得我的想法有意义吗?还是垃圾

让我知道我的解释中有什么不清楚的地方(我打赌会有(。

一些应该有所帮助的建议:

  • 执行线程转储(例如使用visualvm(并查看被阻止的内容
  • 尽量减少分叉任务的数量
  • 考虑迭代而不是递归

最新更新