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

Java concurrency reference: admission, visibility, atomicity and completion

Last updated: 29 Sept 20264 min read
tutorial
IntermediateBy AITrove Editorial

Concurrency design needs separate answers for how work is admitted, how state is shared, how an update is made indivisible and how completion is observed.

Java 8+. This is a complete program using JDK classes.

Match the mechanism to the invariant

A lock protects a compound transition when every participating caller follows the same lock policy. An atomic variable supplies particular indivisible operations on that variable. Volatile supplies visibility and ordering for a field; it does not supply a multi-field transaction.

A semaphore controls permit admission. A blocking queue carries work with a chosen capacity and waiting contract. A future reports a task result, while a timed get bounds a wait rather than automatically cancelling the task. None of these objects provides durable execution after process loss.

The small probe observes a completed worker through Future.get. It then rejects a submission after the owner shuts the executor down. The task result and the admission failure are different outcomes and should have different handling paths.

Use an ownership checklist

Identify the creator and closer of every pool, the maximum pending work, the deadline and cancellation policy, the shared-state invariant and the behavior when shutdown races with submission. A concurrency class name cannot fill in those application decisions.

Working program

Java
import java.util.concurrent.*;
public class WorkerLifecycleReference {
    public static void main(String[] args) throws Exception {
        ExecutorService owner=Executors.newSingleThreadExecutor();
        try{
            Future<Integer> task=owner.submit(()->42);
            System.out.println("result="+task.get(2,TimeUnit.SECONDS));
            owner.shutdown();
            try{owner.submit(()->43);}catch(RejectedExecutionException rejected){System.out.println("Admission closed");}
        }finally{
            owner.shutdownNow();
            if(!owner.awaitTermination(2,TimeUnit.SECONDS))throw new IllegalStateException("Owner did not close");
        }
    }
}

Output

Output
result=42
Admission closed

Costs and boundaries

One task is admitted and one rejection is exercised. This fixed fixture has constant-sized application state. General pool memory scales with retained queued inputs and active task state; worker count alone does not give that memory bound.

Common Mistakes

  • Visibility is not compound atomicity.
  • Successful submission is not successful completion.
  • A pool shutdown is not remote rollback.

Read next

Protected predicates, Cooperative stopping.

java
concurrency-reference
Storage details