Skip to content
AITroveRead. Build. Understand.
Make this comfortable

Java fork/join failures: one failed task does not roll back sibling work

Last updated: 5 Oct 20265 min read
tutorial
AdvancedBy AITrove Editorial

A runtime failure from RecursiveTask.compute propagates through join or invoke. A sibling task may already have run, so failure of the result is not an atomic rollback of side effects.

Operational contract

Keep fork/join computations pure or confine mutations to disjoint owned ranges. The sample validates each shipment quantity before contributing to an aggregate. If one leaf fails, the caller receives a computation failure, but other leaves may have completed. No database or external mutation occurs, so discarding the final sum is safe. If a task writes outside its range, the caller needs separate reconciliation and cancellation; a thrown exception alone will not undo that work. Use an owned pool with a finite batch and record the original cause.

Failure case

A batch contains 47,000 counts and one negative quantity. The validation task throws instead of returning a misleading sum. Other subranges may already have been summed. That wasted computation is acceptable; writing partial totals to a ledger from each leaf would not be, because the exception cannot retract those ledger entries.

Java code

Java
import java.util.concurrent.RecursiveTask;

public class ValidatedShipmentSum extends RecursiveTask<Long> {
    private final int[] quantities;
    private final int start;
    private final int end;

    public ValidatedShipmentSum(int[] quantities, int start, int end) {
        this.quantities = quantities;
        this.start = start;
        this.end = end;
    }

    @Override protected Long compute() {
        if (end - start <= 256) {
            long total = 0;
            for (int index = start; index < end; index++) {
                if (quantities[index] < 0) throw new IllegalArgumentException("Negative quantity at " + index);
                total += quantities[index];
            }
            return total;
        }
        int middle = start + (end - start) / 2;
        ValidatedShipmentSum left = new ValidatedShipmentSum(quantities, start, middle);
        left.fork();
        long rightTotal = new ValidatedShipmentSum(quantities, middle, end).compute();
        return rightTotal + left.join();
    }
}

Performance and ownership cost

A valid batch does O(N) validation and summation. An invalid item can reduce useful work, but parallel siblings may still complete, so the failure path has no fixed early-stop cost. The split threshold limits task count to roughly O(N/256) leaves.

Common Mistakes

  • Do not assume an exception cancels sibling work immediately.
  • Do not write irreversible side effects from each leaf and expect rollback.
  • Do not swallow a validation exception and publish a partial total.

Connected lessons

java
fork/join task ownership
forkjoin-failure-and-sibling-work
Storage details