I Asked DeepSeek Harness to Give Me an Interview Question

DeepSeek HarnessJavaConcurrencyInterview

A GitHub job opening landed in my inbox

Today I opened my inbox and saw a GitHub job opening — the first time I’d ever seen one, so it felt a bit novel, and I clicked in to take a look. Since I’ve been playing with DeepSeek Harness, I handed it the job description, told it about a few of my past roles, and asked it to write me a coding interview question.

The question:

2026-08-18 · Bounded Blocking Queue

Background

ArrayBlockingQueue / LinkedBlockingQueue in java.util.concurrent are industrial-grade implementations. Interviewers love asking candidates to “write your own blocking queue”, because it tests everything at once: choice of concurrency primitives, memory visibility, lock granularity, lost wakeups, interruption semantics, and fairness.

Basic requirements

  1. Do not use the JDK’s built-in BlockingQueue, ArrayBlockingQueue, LinkedBlockingQueue, ConcurrentLinkedQueue, and so on — write it from scratch.
  2. Implement the following interface (you may turn it into an abstract class; just keep the semantics):
public interface BoundedQueue<T> {
    void put(T item) throws InterruptedException;   // blocks when the queue is full
    T take() throws InterruptedException;           // blocks when the queue is empty
    int size();                                     // current element count
    boolean isEmpty();                              // whether it is empty
}
  1. Bounded: take a capacity > 0 in the constructor; put blocks when full, take blocks when empty.
  2. Thread-safe: correct under multiple producers + multiple consumers — no lost data, no duplicates, no returning null, no going out of bounds, and size() never negative or over capacity.
  3. Genuinely blocking, no busy-wait: while (!condition) Thread.sleep(...) or bare spinning doesn’t count.
  4. Interruption semantics: when interrupted while blocked, throw InterruptedException and restore the interrupt flag (Thread.currentThread().interrupt()).

Advanced (if you’re up for it)

  • Timeout versions: boolean offer(T item, long timeout, TimeUnit unit) and T poll(long timeout, TimeUnit unit).
  • Fairness: wake the longest-waiting thread first (think of ReentrantLock(true)’s fair-queue idea).
  • Dual-lock version: can you split it into a put lock + take lock like LinkedBlockingQueue for higher throughput? And what’s the cost?
  • Thought question (no code): why does ArrayBlockingQueue use one lock + two Conditions, while LinkedBlockingQueue uses two locks? When is each appropriate?

Scoring dimensions

Dimension What it looks at
Correctness Is it really safe under concurrency? Is memory visibility (volatile / lock) handled right?
Blocking / wakeup wait/notify or Lock/Condition? Did you write the while-loop condition check (to avoid spurious wakeups / lost wakeup)?
Interruption Does it propagate InterruptedException correctly and restore the interrupt flag?
Performance Lock granularity; can size()/isEmpty() be read lock-free?
Testing How do you prove it’s correct? Multithreaded stress tests, CountDownLatch assistance, even jcstress?

Me

Good question, honestly — and I genuinely couldn’t do it anymore. AI coding has been my downfall.

I first tried hand-writing it in Notepad. When I got to Runnable, I wavered for a second — is that in the java.util package? … no, it’s in java.lang, right…

This won’t do. I’m not ready to retire just yet.


Still, do the problem first — even if it’s copying it down

public class BoundedQueueImpl<T> Implements BoundedQueue<T> {
     private final Object[] items; //use final: the array reference can't be reassigned, but the contents can still change
     private final Object lock = new Object(); //a private member as the lock (vs. `this`) at least avoids strangers locking on it without you knowing who did it
     private int putIndex; //where the next enqueued element goes in the array
     private int takeIndex; //where the next dequeued element comes from in the array
     private int count; //how many elements are currently in the array
     private final int capacity; //I still like declaring it explicitly
     public BoundedQueueImpl(int capacity) {
         if(capacity <= 0) throw new IllegalArgumentException("Capacity should be > 0");
         this.capacity = capacity;
     }
     
     @Override
     public void put(T item) throws InterruptedException {
         synchronized(lock) {
             while(count == capacity) {//full — pitfall #1: can't use `if`, would overflow
                  lock.wait();
             }
             item[putIndex] = item;
             putIndex = (putIndex +1) % capacity;
             count++;
             lock.notifyAll(); //pitfall #2: can't be `notify`, would deadlock
         }
     }
     
     @Override
     @SuppressWarning("unchecked")
     public T take() throws InterruptedException {
         synchronized(lock) {
             while(count == 0) {//empty — same as pitfall #1: can't use `if`, would underflow
                 lock.wait();
             }
             T item = (T)items[takeIndex];
             items[takeIndex] = null;//good habit: allow early GC
             takeIndex = (takeIndex+1) % capacity;
             count--;
             lock.notifyAll();//again, notifyAll
             return item;
         }
     }
     
     @Override
     public int size() {
         synchronized(lock) {//can't omit this — omitting it invites bugs: instruction reordering, consistency...
             return count;
         }
     }
     
     @Override
     public boolean isEmpty() {
         synchronized(lock) {
             return count == 0;
         }
     }
}

AI review

Four bugs (three compile errors + one fatal omission)

Where Problem Fix
Constructor items was never new’d — private final Object[] items; but the constructor never does items = new Object[capacity];, so a final field is left uninitialized → won’t compile; even if it did, the first put would NPE. This is the only logic-level one. Add items = new Object[capacity]; in the constructor.
put item[putIndex] = item; — used the parameter name item as if it were the array items[putIndex] = item;
Class declaration Implements is capitalized implements
Annotation @SuppressWarning @SuppressWarnings
← Back to blog