Closing Channels in Java

import java.util.concurrent.*;

public class ClosingChannels {
    public static void main(String[] args) throws InterruptedException {
        BlockingQueue<Integer> jobs = new ArrayBlockingQueue<>(5);
        CountDownLatch done = new CountDownLatch(1);

        // Here's the worker thread. It repeatedly takes from `jobs`.
        // We use `poll` with a timeout to check if the queue is empty and closed.
        // We use the CountDownLatch to notify when we've processed all jobs.
        new Thread(() -> {
            while (true) {
                try {
                    Integer j = jobs.poll(100, TimeUnit.MILLISECONDS);
                    if (j != null) {
                        System.out.println("received job " + j);
                    } else {
                        System.out.println("received all jobs");
                        done.countDown();
                        return;
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    return;
                }
            }
        }).start();

        // This sends 3 jobs to the worker over the `jobs` queue.
        for (int j = 1; j <= 3; j++) {
            jobs.put(j);
            System.out.println("sent job " + j);
        }
        System.out.println("sent all jobs");

        // We await the worker using the CountDownLatch.
        done.await();

        // In Java, we don't have a direct equivalent to reading from a closed channel.
        // Instead, we can check if the queue is empty after all jobs are processed.
        boolean moreJobs = !jobs.isEmpty();
        System.out.println("more jobs available: " + moreJobs);
    }
}

In this example, we use a BlockingQueue to communicate work to be done from the main thread to a worker thread. When we have no more jobs for the worker, the queue will be empty.

The BlockingQueue interface in Java doesn’t have a built-in concept of closing, unlike channels in Go. Instead, we use a timeout when polling from the queue to detect when no more items are available.

We use a CountDownLatch for synchronization between the main thread and the worker thread, similar to the synchronization approach used in the original example.

To run the program, compile it and use java:

$ javac ClosingChannels.java
$ java ClosingChannels
sent job 1
received job 1
sent job 2
received job 2
sent job 3
received job 3
sent all jobs
received all jobs
more jobs available: false

This example demonstrates how to implement a similar pattern of job distribution and completion signaling in Java, even though Java doesn’t have built-in channels like Go does.