GRPC线程组功能解析及阻塞调用等待资源咨询
GRPC线程状态相关问题解答
1. grpc-default-worker线程的功能
这是gRPC基于Netty实现的IO线程池,核心负责底层网络相关的所有操作:
- 监听TCP连接的建立、断开事件
- 读写socket上的二进制数据
- 处理网络IO的多路复用事件(比如你堆栈里的
epollWait,就是Linux下epoll机制等待网络事件触发)
这种线程在没有网络事件时会处于阻塞等待状态,属于正常的空闲状态,并非异常。
2. grpc-default-executor线程的功能
这是gRPC的通用业务线程池,专门用来执行非IO密集型的逻辑:
- 服务端收到请求后,实际业务方法的调用执行
- 客户端收到响应后的回调逻辑处理
你的堆栈里该线程处于TIMED_WAITING,是因为线程池当前没有待执行的任务,线程在通过SynchronousQueue等待新任务,属于线程池的正常空闲状态,无需过度担忧。
3. IO线程在blockingStub调用时等待的对象
从线程堆栈可以明确看到,它在等待io.grpc.stub.ClientCalls$ThreadlessExecutor。
BlockingStub是gRPC的同步调用方式,发起调用的业务线程(这里是io-pool的线程)会进入阻塞状态,直到收到服务端响应。ThreadlessExecutor是gRPC内部的协调工具,它会等待grpc-default-worker线程完成网络请求的发送、响应的接收和解析,之后唤醒当前阻塞的业务线程并返回调用结果。
附线程堆栈信息
grpc-default-worker线程堆栈
grpc-default-worker-ELG-3-1 THREAD ID: 330 STATE: RUNNABLE stackTrace: java.lang.Thread.State: RUNNABLE at app//io.grpc.netty.shaded.io.netty.channel.epoll.Native.epollWait0(Native Method) at app//io.grpc.netty.shaded.io.netty.channel.epoll.Native.epollWait(Native.java:132) at app//io.grpc.netty.shaded.io.netty.channel.epoll.EpollEventLoop.epollWait(EpollEventLoop.java:286) at app//io.grpc.netty.shaded.io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:351) at app//io.grpc.netty.shaded.io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989) at app//io.grpc.netty.shaded.io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) at app//io.grpc.netty.shaded.io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.base@11.0.11/java.lang.Thread.run(Thread.java:829) Locked ownable synchronizers: - None
grpc-default-executor线程堆栈
grpc-default-executor-76 THREAD ID : 1768 STATE : TIMED_WAITING stackTrace: java.lang.Thread.State: TIMED_WAITING at java.base@11.0.11/jdk.internal.misc.Unsafe.park(Native Method) - parking to wait for <6af9e3ce> (a java.util.concurrent.SynchronousQueue$TransferStack) at java.base@11.0.11/java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:234) at java.base@11.0.11/java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:462) at java.base@11.0.11/java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:361) at java.base@11.0.11/java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:937) at java.base@11.0.11/java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1053) at java.base@11.0.11/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1114) at java.base@11.0.11/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base@11.0.11/java.lang.Thread.run(Thread.java:829) Locked ownable synchronizers: - None
io-pool线程堆栈
io-pool-145 THREAD ID : 1683 STATE : WAITING stackTrace: java.lang.Thread.State: WAITING at java.base@11.0.11/jdk.internal.misc.Unsafe.park(Native Method) - parking to wait for (a io.grpc.stub.ClientCalls$ThreadlessExecutor) at java.base@11.0.11/java.util.concurrent.locks.LockSupport.park(LockSupport.java:194) at app//io.grpc.stub.ClientCalls$ThreadlessExecutor.waitAndDrain(ClientCalls.java:731) at app//io.grpc.stub.ClientCalls.blockingUnaryCall(ClientCalls.java:149) xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx xx at java.base@11.0.11/java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1700) at java.base@11.0.11/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base@11.0.11/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base@11.0.11/java.lang.Thread.run(Thread.java:829) Locked ownable synchronizers: - Locked <41493122> (a java.util.concurrent.ThreadPoolExecutor$Worker)
内容的提问来源于stack exchange,提问作者Shashank Babu
相关产品推荐
相关产品推荐

