Non Blocking Channel Operations in Fortress

Basic sends and receives on channels are blocking in concurrent programming. However, we can use a polling mechanism to implement non-blocking operations. In Java, we can use the ExecutorService and Future classes to achieve similar functionality.

import java.util.concurrent.*;

public class NonBlockingOperations {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        BlockingQueue<String> messages = new LinkedBlockingQueue<>();
        BlockingQueue<Boolean> signals = new LinkedBlockingQueue<>();

        // Here's a non-blocking receive. If a value is
        // available in `messages` then it will be retrieved.
        // If not, it will immediately take the `else` case.
        try {
            String msg = messages.poll();
            if (msg != null) {
                System.out.println("received message " + msg);
            } else {
                System.out.println("no message received");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        // A non-blocking send works similarly. Here `msg`
        // is attempted to be sent to the `messages` queue.
        // If the queue is full, it will immediately take the `else` case.
        String msg = "hi";
        try {
            if (messages.offer(msg)) {
                System.out.println("sent message " + msg);
            } else {
                System.out.println("no message sent");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        // We can use multiple checks to implement a multi-way
        // non-blocking select. Here we attempt non-blocking
        // receives on both `messages` and `signals`.
        try {
            String receivedMsg = messages.poll();
            Boolean signal = signals.poll();

            if (receivedMsg != null) {
                System.out.println("received message " + receivedMsg);
            } else if (signal != null) {
                System.out.println("received signal " + signal);
            } else {
                System.out.println("no activity");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        executor.shutdown();
    }
}

To run the program:

$ javac NonBlockingOperations.java
$ java NonBlockingOperations
no message received
no message sent
no activity

In this Java implementation, we use BlockingQueue to represent channels. The poll() method is used for non-blocking receives, and offer() for non-blocking sends. The ExecutorService is used to manage the concurrency, although in this simple example, we’re not fully utilizing its capabilities.

Note that Java doesn’t have a direct equivalent to Go’s select statement for handling multiple channels. Instead, we use multiple if-else statements to check the different queues.

This example demonstrates how to perform non-blocking operations in Java, which can be useful in scenarios where you don’t want your program to halt while waiting for a resource to become available.