Closing Channels in Groovy

Closing a channel in concurrent programming indicates that no more values will be sent on it. This can be useful to communicate completion to the channel’s receivers. In Groovy, we can simulate this behavior using an ArrayBlockingQueue and a flag to indicate completion.

import java.util.concurrent.ArrayBlockingQueue
import java.util.concurrent.atomic.AtomicBoolean

def main() {
    def jobs = new ArrayBlockingQueue<Integer>(5)
    def done = new ArrayBlockingQueue<Boolean>(1)
    def isChannelClosed = new AtomicBoolean(false)

    // Here's the worker thread. It repeatedly receives
    // from `jobs` with `jobs.poll()`. We use `isChannelClosed`
    // to notify when all jobs have been processed.
    Thread.start {
        while (true) {
            def j = jobs.poll()
            if (j != null) {
                println "received job $j"
            } else if (isChannelClosed.get()) {
                println "received all jobs"
                done.put(true)
                return
            }
        }
    }

    // This sends 3 jobs to the worker over the `jobs`
    // queue, then sets `isChannelClosed` to true.
    (1..3).each { j ->
        jobs.put(j)
        println "sent job $j"
    }
    isChannelClosed.set(true)
    println "sent all jobs"

    // We await the worker using the synchronization approach.
    done.take()

    // Checking if the channel is closed
    println "received more jobs: ${!isChannelClosed.get()}"
}

main()

To run the program, save it as ClosingChannels.groovy and use the groovy command:

$ groovy ClosingChannels.groovy
sent job 1
received job 1
sent job 2
received job 2
sent job 3
received job 3
sent all jobs
received all jobs
received more jobs: false

In this Groovy example, we use an ArrayBlockingQueue to simulate a channel, and an AtomicBoolean to indicate when the “channel” is closed. The worker thread continuously polls the queue for jobs, and checks the isChannelClosed flag to determine when to stop.

The main thread sends jobs to the queue and then sets the isChannelClosed flag to true. The done queue is used for synchronization between the main thread and the worker thread.

This approach provides a similar behavior to closing channels in Go, although it’s not an exact equivalent due to the differences in concurrency models between Go and Groovy/Java.