<Spring Batch> 为什么使 ItemReader 线程安全会导致我们失去可重启性?

Rit*_*ato 3 multithreading spring-batch

我有一个从数据库读取的多线程批处理作业,我担心不同的线程重新读取记录,因为 ItemReader 在 Spring 批处理中不是线程安全的。我浏览了SpringBatch 常见问题部分,其中指出

您可以同步 read() 方法(例如,通过将其包装在执行同步的委托程序中)。请记住,您将失去可重启性,因此最佳做法是将步骤标记为不可重启,并且为了安全(和高效),您还可以在阅读器上设置 saveState=false。

我想知道为什么在这种情况下我会失去重新启动性?可重启性与同步我的读取操作有什么关系?它总是可以再试一次,对吧?另外,这段代码是否足以同步阅读器?

  public SynchronizedItemReader<T> implements ItemReader<T> {
  private final ItemReader<T> delegate; 
  public SynchronizedItemReader(ItemReader<T> delegate) {
    this.delegate = delegate;
  }
  public synchronized T read () {
    return delegate.read();
  }
}
Run Code Online (Sandbox Code Playgroud)

Mic*_*lla 5

将 ItemReader 与多线程一起使用时,缺乏可重启性与读取本身无关。这是关于保存在 update 方法中发生的阅读器的状态。问题是在调用 read() - 提供数据的方法和 update() - 保持状态的方法之间需要协调。当您使用多个线程时,读取器的内部状态(以及因此 update() 调用)可能会也可能不会反映已完成的工作。以使用块大小为 5 并在多个线程上运行的 FlatFileItemReader 为例。您可以让线程 1 读取 5 个项目(更新时间),而线程 2 可以读取额外的 3 个项目。这意味着对更新的调用将保存已读取的 8 个项目。如果线程 2 上的块失败,

这并不是说不可能编写线程安全的 ItemReader。但是,如您上面的示例所示,如果委托是有状态的 ItemReader(也实现了 ItemStream),则状态将不会通过调用 update 正确持久化(实际上,您上面的示例甚至没有采用阶段式阅读器的 ItemStream 方面考虑在内)。