AI agents
Parallelism, Concurrency, and Synchronization
Coordinate parallel agent branches through immutable inputs, ownership, joins, and shared-state controls.
By the end you can
- Define parallel agent execution as an operational contract rather than a capability label
- Contrast Independent parallel calls with Optimistic concurrency in “Two agent branches edited the same configuration and each overwrote the other”
- Trace “Parallel agents can agree because they copied the same error” through a concrete execution path
- Produce “Design a safe parallel stage” with evidence for “Parallelism reduces latency without increasing final-state conflicts”
Visual
Whoever owns the join should not own cancellation
Work is partitioned, branches execute, a shared-state rule keeps them from colliding, and a join decides what the run actually produced. Whoever owns the join should not also own cancellation. Neither test covers the other.
A production orchestrator shows why they are two tests. In a Parallel state the branches all run at once, and the interpreter waits for every one of them to terminate. A Map state takes a MaxConcurrency field: an integer upper bound on how many iterations may run in parallel. The Amazon States Language specification, revised in 2024, writes both of those down. Fan-out width and join semantics are part of the workflow. Cancellation is not written down beside them.
Something does survive a failed fan-out, and the AWS Step Functions Developer Guide says what: “When a parallel state fails, invoked Lambda functions continue to run and activity workers processing a task token are not stopped.”
The branch has ended and the side effect has not. A join that reports a clean failure is telling the truth about the branches and nothing at all about what they left running.
- 1
Partition
Assign non-overlapping work or immutable input snapshots.
- 2
Branch execution
Run tools or agents independently with local budgets.
- 3
Shared-state rule
Use ownership, locks, versions, or append-only events.
- 4
Join
Collect outputs and verify completeness, consistency, and provenance.
- 5
Cancellation
Stop obsolete or losing branches without leaking side effects.
Example
P4, Lost Update: r1[x=100] r2[x=100] w2[x=120] c2 w1[x=130] c1
The failure two branches produce when they edit the same thing already has a name, a paper, and an exact interleaving. The name is P4, Lost Update. It was catalogued in 1995, in a critique of the ANSI SQL isolation levels. The definition there is the whole mechanism in one sentence: “P4 (Lost Update): The lost update anomaly occurs when transaction T1 reads a data item and then T2 updates the data item (possibly based on a previous read), then T1 (based on its earlier read value) updates the data item and commits.”
The history the paper prints is six operations long: H4 = r1[x=100] r2[x=100] w2[x=120] c2 w1[x=130] c1. Both transactions read 100. T2 writes 120 and commits. T1 still holds the value it read before T2 existed. It writes 130 and commits. Nothing raises an error, no lock is violated, and both branches report success. The committed update of T2 is gone. The surviving state, 130, was computed from a value that had already stopped being true.
Two agent branches editing the same configuration reproduce H4 exactly. Tool calls stand in for the reads and writes, and each branch's local tests pass on its own copy.
The same paper adds a second anomaly, P0 (Dirty Write). ANSI SQL-92 does not mention it. The paper concludes that ANSI SQL isolation should be modified to forbid P0 at every isolation level. The guarantee level a system advertises may not exclude the anomaly you actually have.
- Decision at stake: Coordinate parallel agent branches through immutable inputs, ownership, joins, and shared-state controls — the controls that make H4 impossible rather than merely unlikely.
- Hidden assumption: That a branch which has read the state is still entitled to write it. In H4 both transactions read x=100 and both were still permitted to write.
- Primary control question: Which write gets refused, and by what rule? P4 is not repaired by scheduling the branches better; it is repaired by checking at write time that the value read is still the value stored.
- Evidence to collect: Parallelism reduces latency without increasing final-state conflicts — counted as writes detected and refused, not as absence of complaints, because a lost update produces no error to complain about.
Merge semantics have to exist before branches start
Parallelism can reduce latency when branches are independent or when several evidence paths can be explored simultaneously.
Concurrency becomes unsafe when branches mutate shared state, consume the same budget, or make decisions from different versions.
A coordinator should define branch inputs, write ownership, synchronization points, cancellation, and merge semantics before work begins. That is not a new demand made of agent runtimes. Kung and Robinson set it out in 1981, as a requirement rather than a convention: “It is required that any transaction consist of two or three phases: a read phase, a validation phase, and a possible write phase (see Figure 1).”
The order carries the safety. The read phase runs on local copies, so nothing shared has moved yet. The validation phase then decides whether the work is allowed to land. Only after it passes does a write phase touch shared state.
The validation condition is three alternatives on the intersection of read sets and write sets. That is the merge rule stated in advance, in terms of what each branch read and what it now wants to write. A coordinator that decides its merge rule after the branches have landed has deleted the middle phase and kept its name.
Merge rules written after the branches have already run are not rules; they are whichever result happened to land last.
Case
90.2 percent better, at fifteen times the tokens
The costs and the gains have both been published. A lead agent with subagents beat a single agent by 90.2 percent on Anthropic's internal research evaluation. The multi-agent run used roughly fifteen times the tokens of a chat exchange. Anthropic also names the cases that split badly: agents that share context, or depend on each other.
The counterweight has been measured as well. A 2025 paper on multi-agent LLM systems opens on the trade rather than the promise: “Despite enthusiasm for Multi-Agent LLM Systems (MAS), their performance gains on popular benchmarks are often minimal.” Its authors analysed 150 execution traces and built MAST, a taxonomy of 14 failure modes in three categories. Inter-annotator agreement was kappa = 0.88. They released MAST-Data as well: 1600+ annotated traces across 7 popular multi-agent frameworks.
Put side by side, the two results set the terms of the decision. A fan-out can be worth 90.2 percent at fifteen times the tokens. The ways it fails are not mysterious or one-off. There are 14 of them, named and counted across 7 frameworks, catalogued from traces rather than from intuition.
Key idea
Parallel agents can agree because they copied the same error
Multiple branches are not independent when they share prompts, data, tools, or retrieved sources, and a majority vote may amplify a common blind spot rather than provide stronger evidence.
The assumption has been tested head-on, with programs rather than models. Twenty-seven versions of the same anti-missile specification were written independently, 9 at the University of Virginia and 18 at UC Irvine. Every one of them was put through one million randomly generated tests. Knight and Leveson published the result in 1986, and their abstract states it plainly: “The results of the tests revealed that the programs were individually extremely reliable but that the number of tests in which more than one program failed was substantially more than expected.” Coincident failures across versions were far more frequent than independence predicts. The null hypothesis of independent failure was rejected at the 99 percent confidence level.
Independently written turned out not to mean independent. What those 27 versions had in common was a specification, and a shared specification was enough to correlate their errors. Agent branches share considerably more: the same prompt, the same retrieved documents, the same tools, often the same model. Track correlation between branches. Prefer diversity in method or evidence, not only separate model calls.
Agreement among branches that share their sources is not evidence; it is one answer counted several times.
Comparison
Competing strategies for parallel agent execution
Independent parallel calls, optimistic concurrency, and uncontrolled shared mutation are three answers to one question: who is allowed to write.
Only one of the three is written down as a standard. HTTP has a request header for exactly this problem. RFC 9110, published in 2022, says what If-Match is for: “If-Match is most often used with state-changing methods (e.g., POST, PUT, DELETE) to prevent accidental overwrites when multiple user agents might be acting in parallel on the same resource (i.e., to prevent the "lost update" problem).” The obligations are normative. An origin server MUST evaluate the condition before performing the method, MUST NOT perform the method if the condition is false, and MAY respond 412 (Precondition Failed). For a resource used as a semaphore, the RFC advises that the server is “better off being stringent in sending 412 for every failed precondition on an unsafe method.”
That is what optimistic concurrency looks like on the wire: the version a branch read, sent back with the write, and a numbered refusal — 412 — when the version has moved. Independent parallel calls avoid the question entirely. Every branch gets immutable inputs and a separate artifact, so no refusal is ever needed. Uncontrolled shared mutation has no refusal to issue. Every branch succeeds. The difference shows up only in the final state, as it did in H4, after everything has already committed.
The strategy is working when parallelism reduces latency without increasing final-state conflicts. It is failing when parallel agents agree because they copied the same error — an agreement that looks like confirmation and is not.
Independent parallel calls
Branches read shared immutable data and produce separate artifacts.
- Low coordination risk
- Good latency gains
- Simple merge
Optimistic concurrency
Branches update versioned resources and conflicts are detected.
- High throughput
- Needs retries or merge
- Conflict cost
Uncontrolled shared mutation
Branches write the same state without coordination.
- Easy prototype
- Race conditions
- Non-reproducible outcomes
Analogy
A Kitchen With Separate Stations and One Pass
A restaurant kitchen runs its stations in parallel, and tickets, ownership, timing, and the final pass are what turn separate work into one meal. A second cook cannot plate the same dish twice without anyone noticing. A second branch can repeat an entire action invisibly unless the runtime tracks the identity of what was already done.
In a kitchen the cost of the missing ticket is a wasted plate. The documented cost has been higher. The Therac-25 caused six known massive-overdose accidents between June 1985 and January 1987. Leveson and Turner traced one of them, in 1993, to a race condition between the keyboard-handler task and the data-entry routine. The two shared a single completion variable. One flag was answering the wrong question: “But the data-entry completion variable only indicates that the cursor has been down to the command line, not that it is still there. A potential race condition is set up.” AECL's fix was a further shared variable, set by the keyboard handler, to record that the cursor had left the command line.
The flag was not wrong about what it claimed. It answered a question about the past. A second task, running at the same time, read it as an answer about the present. That is a shape worth recognizing in an agent run: a field that records that an action was started, read by a second branch as meaning the action is finished.
Parallel work needs a join contract and explicit control of shared state.
Steps
Design a safe parallel stage
One stage of one workflow, made safe to run in parallel: name the write owner, the join, and the cancellation rule before adding a branch. Then test the design rather than admire it.
That test is more tractable than it sounds. In 2008 four researchers examined 105 randomly selected real-world concurrency bugs from MySQL, Apache, Mozilla and OpenOffice, and reported: “About 92% of the examined concurrency bugs can be reliably triggered by enforcing certain orders among no more than 4 memory accesses.” A race that appears to need luck to reproduce usually needs an order among four or fewer shared accesses. That is small enough to enumerate for a stage you designed yourself, and to force on purpose in a harness.
Two of their other figures should change what you build, not only how you test it. About 34 percent of the non-deadlock bugs involved multiple variables, so a lock per variable is not a fix per bug. About 73 percent of the non-deadlock bugs were not fixed by simply adding or changing locks. The reflex reach for a lock was, in roughly three cases out of four in that sample, not the repair.
So: prove independence from immutable inputs, assign write ownership, version the state that must be mutated, define the join and the conflict rule, and set the cancellation rule. Then seed the branches with a shared wrong assumption and see whether they converge on it. Force the four-access orders you can enumerate. Measure whether the parallel version really finishes sooner without leaving the final state in dispute.
- 1
Prove independence
Show that branches can run from immutable inputs without shared writes.
- 2
Assign ownership
Name which branch may modify each artifact or resource.
- 3
Version shared state
Use compare-and-swap, locks, or append-only events where mutation is necessary.
- 4
Define the join
Specify required outputs, conflict resolution, and evidence checks.
- 5
Set cancellation rules
Stop redundant or invalid branches before further side effects.
Widen the fan-out only after one trajectory is reliable
Parallelism is an optimization after correctness. First make one trajectory reliable, then parallelize work whose dependencies and merge rules are understood.
Before widening a fan-out, ask again whether the branches are independent, or whether they all inherit the same assumption from the same place. Twenty-seven versions written by different people from one shared specification did not clear that bar. The independence hypothesis was rejected at the 99 percent confidence level. Ask which write gets refused, and under what rule, before any branch starts. That is a validation phase between the read and the write, not a merge argued about afterward. And do not assume the obvious remedy is the remedy: among the 105 bugs studied, about 73 percent of the non-deadlock ones were not fixed by adding or changing locks.
The fan-out is paying for itself only when it shortens the run and the merged result is not more contested than the serial one would have been.
Fanning out a trajectory that is not yet reliable buys faster wrong answers and a much harder debugging job.
Key takeaways
- Parallelism can reduce latency when branches are independent or when several evidence paths can be explored simultaneously. Anthropic's reported 90.2 percent gain over a single agent cost roughly fifteen times the tokens of a chat exchange.
- A coordinator should define branch inputs, write ownership, synchronization points, cancellation, and merge semantics before work begins. Kung and Robinson required a read phase, a validation phase, and only then a possible write phase, in 1981.
- The failure has a name and a six-operation trace: P4 (Lost Update), H4 = r1[x=100] r2[x=100] w2[x=120] c2 w1[x=130] c1, catalogued in a 1995 critique of ANSI SQL isolation levels.
- Optimistic concurrency is a wire standard, not a metaphor. RFC 9110 defines If-Match to prevent the lost update problem, with 412 (Precondition Failed) as the refusal an origin server MAY send.
- Track correlation between branches and prefer diversity in method or evidence. Knight and Leveson's 27 independently written versions failed together far more often than independence predicts, over one million tests.
- Test the race instead of reasoning about it. About 92 percent of 105 real-world concurrency bugs were reliably triggerable by ordering no more than 4 memory accesses, and about 73 percent of the non-deadlock ones were not fixed by adding or changing locks.