1Z0-830 · Domain 8 of 10

1Z0-830 Domain 8: Managing Concurrent Code Execution

This section covers running Java code concurrently: creating platform and virtual threads, Runnable and Callable tasks, thread lifecycle, executor services, locks and atomic variables for thread safety, concurrent collections, and parallel streams.

Exam weight estimate
Not published
Official objectives estimate
3
Estimated questions estimate
~5
Suggested study time estimate
8–10 hrs

About 12 min read Reviewed October 2026

Overview

Domain 8 has three objectives. The first covers creating platform and virtual threads, using Runnable and Callable, managing the thread lifecycle, and running tasks through the different ExecutorService types and the concurrent API. The second covers writing thread-safe code with synchronized blocks, Lock implementations, atomic classes and other java.util.concurrent tools. The third covers processing collections concurrently and using parallel streams.

Virtual threads, finalized in Java 21, are the headline addition compared with the Java 17 exam. Expect to create them with Thread.ofVirtual, Thread.startVirtualThread or Executors.newVirtualThreadPerTaskExecutor, and to know how they differ from platform threads. Most questions show short code using executors, futures or shared counters and ask for output or behaviour.

How it's tested

Expect snippets that start threads or submit tasks and print results, along with questions about whether output is fixed. Read for start versus run, shutdown and close calls, the return type of submit, and whether shared state is protected. When the honest answer is that output varies, Oracle usually offers that as an option.

  • Deterministic or not

    Several threads update shared data, and you decide whether the printed total is fixed or could vary between runs.

  • Executor behaviour

    Tasks are submitted with submit, invokeAll or schedule, and you choose what get returns, when the executor stops, or which exception appears.

  • Virtual thread facts

    A snippet creates virtual threads, and you identify their daemon status, how to start them, or how they compare with pooled platform threads.

Reasoning it through

Two threads each run a loop that increments a shared int field 1,000 times with count++, and the main thread joins both before printing. Many expect 2000. count++ is a read, add and write sequence, so updates can interleave and be lost, and the printed value can be 2000 or lower. Replacing the field with an AtomicInteger and calling incrementAndGet would guarantee 2000.

Objectives 3

Official objectives from the Oracle outline, in outline order.

8.1 Create both platform and virtual threads. Use both Runnable and Callable objects, manage the thread lifecycle, and use different Executor services and concurrent API to run tasks.Thread creation, task types, thread states, executors, futures and scheduled tasks.
What it means
A thread runs a task concurrently with other threads. Platform threads wrap operating system threads, while virtual threads are lightweight threads scheduled by the JVM onto a small pool of carrier threads. Tasks are written as Runnable, which returns nothing, or Callable, which returns a value and may throw checked exceptions. Executor services manage threads for you and return Future objects.
What to understand
Create platform threads with new Thread(r), Thread.ofPlatform() or executors, and virtual threads with Thread.ofVirtual().start(r), Thread.startVirtualThread(r) or Executors.newVirtualThreadPerTaskExecutor(). Virtual threads are always daemon threads, so the JVM can exit without waiting for them, and they are meant to be created per task rather than pooled. Calling start launches a new thread, calling run executes on the current thread, and starting a thread twice throws IllegalThreadStateException. States are NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING and TERMINATED, and join waits for completion. submit accepts Runnable or Callable and returns a Future; get blocks and wraps task exceptions in ExecutionException. Know invokeAll, invokeAny, shutdown versus shutdownNow, awaitTermination, close, and ScheduledExecutorService with schedule, scheduleAtFixedRate and scheduleWithFixedDelay.
How it shows up
Expect code using virtual thread builders, Future.get results, start versus run, and executors closed in try-with-resources.
Common confusion
Thinking virtual threads should be pooled like platform threads, or that shutdown stops tasks already running.
8.2 Develop thread-safe code, using locking mechanisms and concurrent API.Race conditions, synchronized, Lock, atomics, coordination classes and liveness problems.
What it means
Thread-safe code produces correct results when several threads access shared data. Java provides intrinsic locks through synchronized methods and blocks, explicit locks such as ReentrantLock and ReentrantReadWriteLock, atomic classes such as AtomicInteger and AtomicLong, and coordination classes such as CountDownLatch and CyclicBarrier.
What to understand
A synchronized instance method locks on this, a static synchronized method locks on the Class object, and a synchronized block locks on the object you name, so two threads only exclude each other when they use the same lock. ReentrantLock requires an explicit unlock, normally in a finally block; tryLock returns immediately with a boolean, and unlocking a lock you do not hold throws IllegalMonitorStateException. Atomic classes offer methods such as incrementAndGet, getAndIncrement, compareAndSet and updateAndGet. volatile guarantees visibility of writes but not atomicity of compound actions such as count++. Recognise deadlock, where threads wait on each other's locks forever, starvation, and livelock. In Java 21, a virtual thread that blocks while holding a synchronized lock pins its carrier thread, which is one reason ReentrantLock is often suggested for virtual-thread code.
How it shows up
Expect shared counters with and without synchronization, Lock code missing unlock, and scenarios naming a liveness problem.
Common confusion
Believing volatile makes count++ safe, or that synchronizing on different objects still prevents interference.
8.3 Process Java collections concurrently and utilize parallel streams.Concurrent collections, ConcurrentModificationException and parallel stream behaviour.
What it means
Standard collections such as ArrayList and HashMap are not safe for concurrent modification. The java.util.concurrent package supplies thread-safe alternatives, including ConcurrentHashMap, CopyOnWriteArrayList, ConcurrentLinkedQueue and blocking queues such as LinkedBlockingQueue. Parallel streams split work across the common ForkJoinPool.
What to understand
Modifying an ArrayList while iterating it, even on one thread, typically throws ConcurrentModificationException, while CopyOnWriteArrayList iterates over a snapshot and never throws it. ConcurrentHashMap supports atomic compound operations such as merge, compute and putIfAbsent, and rejects null keys and values. Collections.synchronizedList wraps a list with locking, but iteration still needs manual synchronization. A parallel stream may process elements in any order, so forEach output varies, while collect and reduce with an associative operation and neutral identity give consistent results. Lambdas that add to a shared ArrayList from a parallel stream are unsafe; use a collector instead.
How it shows up
Expect CopyOnWriteArrayList iteration output, ConcurrentHashMap merge results and parallel streams writing to shared lists.
Common confusion
Thinking Collections.synchronizedList makes iteration safe without an explicit lock.

High-yield concepts

The terms, rules and formulas this domain turns into questions most often.

  • Virtual thread

    Lightweight JVM-scheduled thread, standard since Java 21.

    Remember
    Always daemon; create one per task.
    Tested as
    Creation and behaviour questions.
    Trap
    Putting virtual threads in a fixed pool.
  • start versus run

    start creates a new thread; run is a plain method call.

    Remember
    Calling start twice throws IllegalThreadStateException.
    Tested as
    Output and thread-name questions.
    Trap
    Expecting run to execute concurrently.
  • Callable

    Task that returns a value and may throw checked exceptions.

    Remember
    Submitted with submit or invokeAll.
    Tested as
    Future result questions.
    Trap
    Passing it to new Thread directly.
  • Future.get

    Blocks until a result is ready.

    Remember
    Task failures arrive as ExecutionException.
    Tested as
    Exception and blocking questions.
    Trap
    Expecting the original exception type to be thrown.
  • ExecutorService.close

    AutoCloseable since Java 19.

    Remember
    Waits for submitted tasks to finish.
    Tested as
    try-with-resources executors.
    Trap
    Thinking executors cannot be used in try headers.
  • shutdown versus shutdownNow

    Orderly stop versus attempted interruption.

    Remember
    shutdown lets queued tasks finish.
    Tested as
    Lifecycle questions.
    Trap
    Expecting shutdown to cancel running work.
  • ReentrantLock

    Explicit lock with tryLock and fairness options.

    Remember
    Always unlock in finally.
    Tested as
    Lock usage questions.
    Trap
    Forgetting unlock and blocking other threads.
  • AtomicInteger

    Lock-free thread-safe integer.

    Remember
    incrementAndGet returns the new value; getAndIncrement the old.
    Tested as
    Shared counter questions.
    Trap
    Mixing up the return values.
  • volatile

    Visibility guarantee for a field.

    Remember
    Not atomic for read-modify-write.
    Tested as
    Race condition questions.
    Trap
    Using it to fix count++.
  • ConcurrentHashMap

    Thread-safe map with atomic compound methods.

    Remember
    Rejects null keys and values.
    Tested as
    Concurrent update questions.
    Trap
    Expecting null support as in HashMap.
  • CopyOnWriteArrayList

    List that copies on every write.

    Remember
    Iterators see a snapshot and never throw ConcurrentModificationException.
    Tested as
    Iteration-while-modifying questions.
    Trap
    Expecting new elements to appear during iteration.
  • Deadlock

    Threads waiting on each other's locks forever.

    Remember
    Consistent lock ordering prevents it.
    Tested as
    Liveness scenario questions.
    Trap
    Confusing it with livelock, where threads stay active.

Side by side

Concepts candidates mix up, compared on the point that decides the answer.

Platform and virtual threads

ConceptMeaningKey differenceCommon trap
Platform thread Wrapper over an OS thread Costly; suits CPU-bound work and pooling Creating millions of them
Virtual thread JVM-managed thread on carrier threads Cheap; suits blocking I/O tasks; always daemon Pooling them or calling setDaemon(false)
newVirtualThreadPerTaskExecutor Executor creating one virtual thread per task No pool size to tune Expecting a fixed number of threads

Thread-safety tools

ConceptMeaningKey differenceCommon trap
synchronized Intrinsic lock on an object or class Automatic release on exit Locking on different objects
ReentrantLock Explicit lock object tryLock, timeouts and fairness Missing unlock in finally
Atomic classes Lock-free single-variable updates compareAndSet and increment methods Using them for multi-variable invariants
volatile Visibility of writes across threads No mutual exclusion Assuming count++ becomes atomic

Exam traps

Each trap is an answer that looks right. Learn the clue that should change your mind.

  1. Fixed total

    What candidates pick
    Picks the exact expected count for threads using count++.
    Why it looks right
    Each thread performs the right number of increments.
    Why it's wrong
    count++ is not atomic, so concurrent updates can be lost and the result can vary.

    Clue to watch for A shared int field updated without synchronization or atomics.

  2. run is concurrent

    What candidates pick
    Assumes calling run prints from a new thread.
    Why it looks right
    run contains the thread's code.
    Why it's wrong
    Only start creates a new thread; calling run executes synchronously on the caller's thread.

    Clue to watch for thread.run() in place of thread.start().

  3. Virtual threads keep JVM alive

    What candidates pick
    Expects the program to wait for an unjoined virtual thread to finish.
    Why it looks right
    Platform threads created with new Thread are non-daemon by default.
    Why it's wrong
    Virtual threads are always daemon, so main can finish and the JVM can exit before they print.

    Clue to watch for A virtual thread started without join or an executor close.

  4. volatile fixes races

    What candidates pick
    Chooses volatile to make a shared counter correct.
    Why it looks right
    It is the concurrency keyword for fields.
    Why it's wrong
    volatile ensures visibility only; the read-modify-write of count++ still interleaves without a lock or atomic class.

    Clue to watch for A volatile int incremented by several threads.

  5. shutdown cancels tasks

    What candidates pick
    Expects queued tasks to be discarded after shutdown.
    Why it looks right
    The name suggests stopping immediately.
    Why it's wrong
    shutdown refuses new tasks but lets submitted ones finish; shutdownNow attempts to interrupt and returns waiting tasks.

    Clue to watch for Tasks submitted before a shutdown call.

  6. synchronizedList iteration

    What candidates pick
    Assumes iterating a synchronized wrapper is safe without extra locking.
    Why it looks right
    Every method on the wrapper is synchronized.
    Why it's wrong
    Iteration spans many calls, so you must hold the list's lock manually during the loop.

    Clue to watch for A for-each over a Collections.synchronizedList result.

Answer framework

Use this sequence to judge what concurrent code will actually do.

  1. Identify how each task starts: start, run, an executor submit, a virtual thread builder, or a parallel stream, and which thread executes it.
  2. Locate every piece of shared mutable state and check whether it is protected by the same lock, an atomic class or a concurrent collection.
  3. Decide whether ordering is enforced; if threads interleave freely and nothing enforces order, prefer the option saying output cannot be determined.
  4. Check lifecycle calls such as join, Future.get, shutdown, close and awaitTermination, plus daemon status, to see whether main waits for work to finish.
  5. Account for exceptions: ExecutionException from get, IllegalThreadStateException from double start, and ConcurrentModificationException from unsafe iteration.

Practice question

A service computes a value on a virtual thread. Assuming main declares throws Exception, what does this print? try (var ex = Executors.newVirtualThreadPerTaskExecutor()) { Future<Integer> f = ex.submit(() -> 6 * 7); System.out.print(f.get() + " "); } System.out.print(Thread.currentThread().isVirtual());

Choose one answer

Want more like this? The 1Z0-830 practice test has questions for every domain.

Checklist

0 of 12

Tick each one you can do without notes. Your ticks stay in this browser.

Study strategy

Start with the lifecycle. Write a program that creates a platform thread and a virtual thread, prints their names and isVirtual values, and compares start with run. Then submit Runnable and Callable tasks to a fixed thread pool, a virtual-thread-per-task executor and a scheduled executor, using get, invokeAll and close in try-with-resources. Make one task throw so you see ExecutionException.

Next, break things on purpose. Increment a shared int from two threads many times and print the total several times; then fix it with synchronized, with ReentrantLock and with AtomicInteger, and compare. Mark the field volatile to show that alone does not fix the race.

Finally, cover collections and parallel streams. Modify an ArrayList during iteration, then repeat with CopyOnWriteArrayList. Use ConcurrentHashMap.merge from several tasks. Run a parallel stream with forEach and forEachOrdered and compare the output. Keep a list of the questions where the right answer was that output cannot be determined, since recognising them is a skill in itself.

FAQ

How much of 1Z0-830 is Domain 8, Managing Concurrent Code Execution?

Oracle does not publish a weight for this section. It has three objectives, and we plan for about five questions, several involving virtual threads or executors.

Are virtual threads final in Java 21?

Yes. Virtual threads became a standard feature in Java 21 through JEP 444, so they are fully in scope for this exam.

Is structured concurrency on the exam?

StructuredTaskScope was a preview API in Java 21. Oracle exams target standard features, so concentrate on threads, executors and the established concurrent API.

Should I pool virtual threads?

No. Virtual threads are cheap, so the recommended approach is one per task, for example with Executors.newVirtualThreadPerTaskExecutor, rather than a fixed pool.

What does Future.get throw if the task fails?

It throws ExecutionException, with the task's original exception available through getCause. It can also throw InterruptedException if the waiting thread is interrupted.

Do I need to know the Fork/Join framework in depth?

The objectives do not name it. Know that parallel streams use the common ForkJoinPool and focus on correctness of parallel results.

Test your Domain 8 knowledge

You have reviewed platform and virtual threads, Runnable and Callable, executors, locks, atomics, concurrent collections and parallel streams. Check whether you can tell fixed output from timing-dependent output.

Keep going