Mastering gRPC Java Clients: Blocking, Async, and Future Stubs Explained

This guide walks through three ways to create gRPC Java clients—newBlockingStub, newStub, and newFutureStub—showing their code, usage patterns, and performance characteristics, while also providing a simple server implementation for testing.

FunTester
FunTester
FunTester
Mastering gRPC Java Clients: Blocking, Async, and Future Stubs Explained

Server implementation

The gRPC service extends HelloServiceGrpc.HelloServiceImplBase and overrides executeHi. The method builds a HelloResponse whose msg field concatenates a greeting, the requester's name, and the current date obtained from Time.getDate(). It then sleeps for one second ( SourceCode.sleep(1.0)) to simulate processing latency, logs the incoming user name, and sends the response via responseObserver.onNext() followed by responseObserver.onCompleted().

package com.funtester.grpc;

import com.funtester.frame.SourceCode;
import com.funtester.fungrpc.HelloRequest;
import com.funtester.fungrpc.HelloResponse;
import com.funtester.fungrpc.HelloServiceGrpc;
import com.funtester.utils.Time;
import io.grpc.stub.StreamObserver;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class HelloServiceImpl extends HelloServiceGrpc.HelloServiceImplBase {
    private static final Logger logger = LogManager.getLogger(HelloServiceImpl.class);

    @Override
    public void executeHi(HelloRequest request, StreamObserver<HelloResponse> responseObserver) {
        HelloResponse response = HelloResponse.newBuilder()
                .setMsg("你好 " + request.getName() + Time.getDate())
                .build();
        SourceCode.sleep(1.0); // simulate delay
        logger.info("用户{}来了", request.getName());
        responseObserver.onNext(response);
        responseObserver.onCompleted();
    }
}

Synchronous (blocking) client – newBlockingStub

This stub provides a traditional request‑response flow. The client creates a ManagedChannel to localhost:8080, builds a HelloServiceBlockingStub with optional gzip compression, and repeatedly calls executeHi. Each call blocks until the server returns a HelloResponse, after which the client prints the msg field.

package com.funtest.grpc;

import com.funtester.frame.SourceCode;
import com.funtester.fungrpc.HelloRequest;
import com.funtester.fungrpc.HelloResponse;
import com.funtester.fungrpc.HelloServiceGrpc;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;

public class BlockClient extends SourceCode {
    public static void main(String[] args) {
        ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 8080)
                .usePlaintext()
                .build();
        HelloServiceGrpc.HelloServiceBlockingStub stub =
                HelloServiceGrpc.newBlockingStub(channel).withCompression("gzip");
        HelloRequest request = HelloRequest.newBuilder()
                .setName("FunTester")
                .build();
        for (int i = 0; i < 5; i++) {
            HelloResponse resp = stub.executeHi(request);
            output("收到响应: " + resp.getMsg());
        }
        channel.shutdown();
    }
}

Pure asynchronous client – newStub

The asynchronous stub returns immediately; results are delivered through a StreamObserver. The client creates the stub, defines an observer that handles onNext (printing the message), onError (printing the error), and onCompleted (no action), then issues several requests. Because the calls are non‑blocking, they are processed concurrently on gRPC’s default executor threads.

package com.funtest.grpc;

import com.funtester.frame.SourceCode;
import com.funtester.fungrpc.HelloRequest;
import com.funtester.fungrpc.HelloResponse;
import com.funtester.fungrpc.HelloServiceGrpc;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import io.grpc.stub.StreamObserver;

public class AsyncClient extends SourceCode {
    public static void main(String[] args) {
        ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 8080)
                .usePlaintext()
                .build();
        HelloServiceGrpc.HelloServiceStub stub =
                HelloServiceGrpc.newStub(channel).withCompression("gzip");
        HelloRequest request = HelloRequest.newBuilder()
                .setName("FunTester")
                .build();
        StreamObserver<HelloResponse> responseObserver = new StreamObserver<HelloResponse>() {
            @Override
            public void onNext(HelloResponse value) {
                output(value.getMsg());
            }
            @Override
            public void onError(Throwable t) {
                output(t.getMessage());
            }
            @Override
            public void onCompleted() {}
        };
        for (int i = 0; i < 5; i++) {
            stub.executeHi(request, responseObserver);
        }
        // Give async calls time to finish before shutting down
        sleep(2000);
        channel.shutdown();
    }
}

Future‑based client – newFutureStub

The future stub returns a ListenableFuture<HelloResponse>. It can be used synchronously by invoking get() on each future, or asynchronously by collecting futures and processing them later. The example demonstrates both patterns.

package com.funtest.grpc;

import com.funtester.frame.SourceCode;
import com.funtester.fungrpc.HelloRequest;
import com.funtester.fungrpc.HelloResponse;
import com.funtester.fungrpc.HelloServiceGrpc;
import com.google.common.util.concurrent.ListenableFuture;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;

public class FutureClient extends SourceCode {
    public static void main(String[] args) throws Exception {
        ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 8080)
                .usePlaintext()
                .build();
        HelloServiceGrpc.HelloServiceFutureStub stub =
                HelloServiceGrpc.newFutureStub(channel).withCompression("gzip");
        HelloRequest request = HelloRequest.newBuilder()
                .setName("FunTester")
                .build();
        // Synchronous style: block on each future
        for (int i = 0; i < 5; i++) {
            ListenableFuture<HelloResponse> future = stub.executeHi(request);
            HelloResponse resp = future.get();
            output(resp.getMsg());
        }
        // Asynchronous style: collect futures then retrieve results
        java.util.List<ListenableFuture<HelloResponse>> futures = new java.util.ArrayList<>();
        for (int i = 0; i < 5; i++) {
            futures.add(stub.executeHi(request));
        }
        for (ListenableFuture<HelloResponse> f : futures) {
            output(f.get().getMsg());
        }
        channel.shutdown();
    }
}

Behavior comparison

Running the three clients against the server yields the following observations:

Blocking stub : Calls are processed sequentially; each request waits for the previous one to complete (approximately one‑second interval due to the server‑side sleep).

Asynchronous stub : All requests are dispatched immediately; responses arrive concurrently on separate executor threads, showing identical timestamps for the server‑side processing.

Future stub : Can be used either way. When get() is called immediately, the pattern behaves like the blocking stub. When futures are collected first and resolved later, the calls are effectively parallel, similar to the async stub.

These three stub types give developers flexibility to choose between simple synchronous code, fully asynchronous callbacks, or a hybrid future‑based approach when integrating gRPC services in Java applications.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaAsynchronousgRPCclientBlockingFuturestub
FunTester
Written by

FunTester

10k followers, 1k articles | completely useless

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.