−65% Most banks now $169 $59.
Coding · 8 min read

Anthropic's Image Processor Coding Question

Anthropic likes one problem that grows from a clean single-threaded design into a concurrency question under load. This image processor is asked over the phone and on-site. You build the simple version first, then the interviewer turns up the parallelism. Here is the full question, Java for both parts, and the rubric.


The question

Design an image processor that executes image-processing jobs. Implement a single processor first: an external API to submit a job, query its status and result, and cancel it. Then extend it to a multi-processor that runs jobs in parallel across a worker pool, preserving submission order and protecting shared state.

Input may be the image or a reference (URL or blob). The processing operation is an abstract pipeline. Discuss throughput and latency trade-offs.

The trap is jumping to threads immediately. Build the single-processor version with a clean external API and a job lifecycle first, because Part 2 is then a swap of the execution layer, not a rewrite.

Part 1 · Single processor

A submit-query-cancel API, a FIFO queue, one worker thread, and a status per job. Failures are isolated to the job that caused them, and only queued jobs can be cancelled.

import java.util.*;
import java.util.concurrent.*;
import java.util.function.Function;

class ImageProcessor {
    enum Status { QUEUED, RUNNING, DONE, FAILED, CANCELLED }

    private static final class Job {
        final String id;
        final byte[] input;
        final Function<byte[], byte[]> pipeline;
        volatile Status status = Status.QUEUED;
        volatile byte[] result;
        Job(String id, byte[] input, Function<byte[], byte[]> pipeline) {
            this.id = id; this.input = input; this.pipeline = pipeline;
        }
    }

    private final Map<String, Job> jobs = new ConcurrentHashMap<>();
    private final BlockingQueue<Job> queue = new LinkedBlockingQueue<>();
    private final Thread worker = new Thread(this::runLoop, "image-worker");
    private volatile boolean running = true;

    ImageProcessor() { worker.start(); }

    // ---- External API ----
    String submit(byte[] input, Function<byte[], byte[]> pipeline) {
        if (input == null || pipeline == null) throw new IllegalArgumentException("bad job");
        String id = UUID.randomUUID().toString();
        Job job = new Job(id, input, pipeline);
        jobs.put(id, job);
        queue.add(job);
        return id;
    }

    Status status(String id) { Job j = jobs.get(id); return j == null ? null : j.status; }
    byte[] result(String id) { Job j = jobs.get(id); return j != null && j.status == Status.DONE ? j.result : null; }

    boolean cancel(String id) {
        Job j = jobs.get(id);
        if (j == null) return false;
        synchronized (j) {                       // only queued jobs can be cancelled
            if (j.status == Status.QUEUED) { j.status = Status.CANCELLED; return true; }
            return false;
        }
    }

    // ---- Single worker ----
    private void runLoop() {
        while (running) {
            Job job;
            try { job = queue.take(); } catch (InterruptedException e) { break; }
            synchronized (job) {
                if (job.status == Status.CANCELLED) continue;
                job.status = Status.RUNNING;
            }
            try {
                job.result = job.pipeline.apply(job.input);   // run the pipeline
                job.status = Status.DONE;
            } catch (Throwable t) {
                job.status = Status.FAILED;                   // isolate the failure
            }
        }
    }

    void shutdown() { running = false; worker.interrupt(); }
}

Part 2 · Multi-processor

Swap the single worker for a fixed pool that drains the same thread-safe queue. The BlockingQueue and ConcurrentHashMap are already the synchronization points, so the worker loop is unchanged. Submission order is preserved for dispatch by the FIFO queue; parallel completion is not ordered, so if consumers need ordered output you assign a sequence number at submit and emit through a reorder buffer.

// Replaces the single worker in Part 1. Everything else stays the same.
private final ExecutorService pool;
private final AtomicLong seq = new AtomicLong();   // submission order, if results must be ordered

ImageProcessor(int workers) {
    pool = Executors.newFixedThreadPool(workers);
    for (int i = 0; i < workers; i++) pool.submit(this::runLoop);  // N workers, one shared queue
}

@Override void shutdown() {
    running = false;
    pool.shutdownNow();        // interrupt in-flight workers, drain none
}

// Ordering note: dispatch is FIFO, but completion is not. If the caller needs
// results in submission order, tag each job with seq.getAndIncrement() and push
// finished jobs through a PriorityQueue keyed by seq before handing them out.

Per-job state stays guarded by synchronized(job), so cancellation and the running flag never race. Throughput scales with the pool size up to the point your pipeline saturates CPU or memory, which is the latency-versus-throughput trade-off the interviewer wants you to name.

How Anthropic scores it

Dimension Weak Strong
API designLeaks the queue or threads to callersClean submit / status / result / cancel that hides execution
Single firstJumps straight to threadsBuilds a correct single-processor, then swaps the execution layer
Thread safetyUnguarded shared maps and flagsConcurrent collections plus per-job locking for state changes
OrderingAssumes parallel results stay orderedNames that completion reorders and proposes a seq + reorder buffer
Failure isolationOne bad job kills the workerCatches per job, marks FAILED, keeps the pool alive
ShutdownLeaves threads runningGraceful shutdown that interrupts in-flight work

The whole question rewards the same instinct: design the single-threaded version so cleanly that concurrency is a swap, not a rewrite.

This is one question of 21 pages

Get the full Anthropic question bank

The full Anthropic bank carries the coding and systems rounds, each problem with its follow-ups and a rubric, compiled from people familiar with the process and cross-verified across sources.

Anthropic interview FAQ

What does the Anthropic coding interview ask?+

Often a build-then-scale problem: design a clean component first, then extend it to run concurrently with a worker pool. The interviewer probes thread safety, ordering, failure isolation, and graceful shutdown rather than tricky algorithms.

Is the Anthropic interview heavy on algorithms?+

Less than most. The emphasis is on systems thinking and clean concurrent design: queues, futures, worker pools, and what happens when a job fails or the process shuts down mid-flight.

What language should I use for the Anthropic interview?+

Any mainstream language. This guide uses Java because its concurrency primitives (ExecutorService, BlockingQueue, ConcurrentHashMap) map directly onto the design. Python or Go are equally accepted.

Where can I find real Anthropic interview questions?+

Pichup maintains an Anthropic question bank compiled from people familiar with the process, with the coding and systems questions, their follow-ups, and rubrics. The question in this guide is one of them.