I hope this message finds you well. Thank you for all the work you are doing to improve the Java platform.
I wanted to share some thoughts from a small experiment I’ve been running with structured concurrency. The idea was to mimic (to some extent) Go’s goroutines and channels, modeling an N:M producer–consumer fan-out using StructuredTaskScope together with ArrayBlockingQueue as a “channel.” The intention is to build groups of task pipelines step by step that can be executed in parallel. Here’s a simplified snippet that captures the idea: void main(){ var producerChannel = new ArrayBlockingQueue<HttpRequest>(100); var consumerChannel = new ArrayBlockingQueue<HttpResponse<String>>(3); var client = HttpClient.newBuilder().build(); var request = HttpRequest.newBuilder() .uri(URI.create("some url")) .build(); try(var routine = StructuredTaskScope.open()){ for(var i = 0; i < 100; i++){ routine.fork(() -> sendRequest(producerChannel, consumerChannel, client)); producerChannel.put(request); } routine.fork(() -> processResponse(consumerChannel)); routine.join(); } catch (InterruptedException e) { throw new RuntimeException(e); } } Void sendRequest(ArrayBlockingQueue<HttpRequest> producerChannel, ArrayBlockingQueue<HttpResponse<String>> consumerChannel, HttpClient client) throws InterruptedException, IOException { var req = producerChannel.take(); var res = client.send(req, HttpResponse.BodyHandlers.ofString()); consumerChannel.put(res); return null; } Void processResponse(ArrayBlockingQueue<HttpResponse<String>> consumerChannel) throws InterruptedException { for (var i = 0; i < 100; i++){ var value = consumerChannel.take().body(); println(value); } var value = consumerChannel.take().body(); println(value); return null; } One thing I noticed is that having to declare Void and return null introduces a bit of noise. This ceremony is required because Runnable doesn’t allow checked exceptions in its contract (and never will, for backwards compatibility). Yet, in practice, many real-world tasks don’t return values directly — instead, they write to or consume from buffers. This makes the Void return type and return null feel redundant. I was wondering: would it be worth considering the addition of a Runnable-like functional interface that permits checked exceptions? Thank you for your time and consideration. I’d love to hear your thoughts. Best regards and always yours. David Grajales Cárdenas.