ThreadManager.java
package org.example.testRpc;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
public class ThreadManager {
/*** 业务线程 */
public static ExecutorService logicThread = Executors.newSingleThreadExecutor(r -> {
Thread t = new Thread(r);
t.setName("LogicThread");
return t;
});
/*** 服务端业务线程 */
public static ScheduledExecutorService scheduleThread = Executors.newScheduledThreadPool(1, r -> {
Thread t = new Thread(r);
t.setName("RpcThread");
return t;
});
public static void init() {
}
}
RpcManager.java
package org.example.testRpc;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;
@Slf4j
public class RpcManager {
/*** key:rpc内部请求唯一标识 value:一次请求*/
public static Cache<Long, CompletableFuture> map = CacheBuilder.newBuilder()
.expireAfterAccess(1, TimeUnit.HOURS)
.expireAfterWrite(1, TimeUnit.HOURS)
.maximumSize(50000)
.build();
/*** 内部请求序列号 */
public static AtomicLong seqNumObj = new AtomicLong(0);
/**
* 发起rpc请求
*
* @param req 请求
* @param resClass 返回的类
* @param consumer 回调
*/
public static <REQ, RES> void sendRpcRequest(REQ req, Class<RES> resClass, Consumer<RpcResponseData<RES>> consumer) {
CompletableFuture<RES> c = new CompletableFuture<>();
// 设置20s后超时返回null
c.completeOnTimeout(null, 20, TimeUnit.SECONDS);
// 模拟发起了一次rpc请求
long seqNum = seqNumObj.incrementAndGet();
map.put(seqNum, c);
// 得到结果后,指定的es就是要回到的线程LogicThread
c.whenCompleteAsync((ret, e) -> {
if (e != null) {
log.error("error=", e);
consumer.accept(new RpcResponseData<>(RPCResultEnum.EXCEPTION, null));
return;
}
log.info("[客户端]收到服务端的处理结果seqNum={}", seqNum);
if (ret == null) {
log.error("[客户端]判断出:rpc超时!!! 请求类型={} 期待返回类型是{}", req.getClass(), resClass);
consumer.accept(new RpcResponseData<>(RPCResultEnum.TIMEOUT, null));
return;
}
if (!resClass.isInstance(ret)) {
log.error("[客户端]判断出:返回类型错误!!! 请求类型={}, 期待服务端返回类型是{},实际返回类型是{}", req.getClass(), resClass, ret.getClass());
consumer.accept(new RpcResponseData<>(RPCResultEnum.TYPE_ERROR, null));
return;
}
consumer.accept(new RpcResponseData<>(RPCResultEnum.OK, ret));
}, ThreadManager.logicThread);
log.info("[客户端]发起rpc请求req={}, reqNum={}", req, seqNum);
// TODO 通过网络发起调用
remoteCall(req, seqNum);
}
private static <REQ> void remoteCall(REQ req, long seqNum) {
ThreadManager.scheduleThread.schedule(() -> {
log.info("[服务端]开始处理请求seq={}, seqNum={}, 还有任务数量taskSize={}", req, seqNum, map.asMap().size());
try {
// 模拟在远端处理完毕后,1s给回应
TimeUnit.MILLISECONDS.sleep(ThreadLocalRandom.current().nextInt(500, 3000));
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("[服务端]处理请求完毕seq={}, seqNum={}", req, seqNum);
// 这里直接移除
CompletableFuture completableFuture = map.asMap().remove(seqNum);
log.info("[服务端]还有任务数量taskSize={}", map.asMap().size());
if (completableFuture == null) {
log.error("seqNum={}没有对应的CompletableFuture", seqNum);
return;
}
int res = 3;
// String res = "abc";
completableFuture.complete(res);
}, 0, TimeUnit.SECONDS);
}
}
RpcResponseData.java
package org.example.testRpc;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class RpcResponseData<RES> {
private RPCResultEnum result;
private RES res;
}
RpcResultEnum.java
package org.example.testRpc;
import lombok.Getter;
public enum RPCResultEnum {
OK("成功"),
EXCEPTION("异常"),
TIMEOUT("超时"),
TYPE_ERROR("服务器返回类型错误"),
;
@Getter
private String desc;
RPCResultEnum(String desc) {
this.desc = desc;
}
}
Main.java
package org.example.testRpc;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class Main {
public static void main(String[] args) {
ThreadManager.init();
// 模拟在业务线程提交一个任务,其实就是处理玩家的请求
ThreadManager.logicThread.execute(() -> {
RpcManager.sendRpcRequest("abc", Integer.class, (res) -> {
if (res.getResult() != RPCResultEnum.OK) {
log.info("rpc请求失败,reason={}!!!", res.getResult().getDesc());
return;
}
log.info("得到返回:{}", res.getRes());
});
});
}
}
/*
正常情况:
16:03:10.636 [LogicThread] INFO org.example.testRpc.RpcManager -- [客户端]发起rpc请求req=abc, reqNum=1
16:03:10.649 [RpcThread-1] INFO org.example.testRpc.RpcManager -- [服务端]开始处理请求seq=abc, seqNum=1, 还有任务数量taskSize=1
16:03:11.912 [RpcThread-1] INFO org.example.testRpc.RpcManager -- [服务端]处理请求完毕seq=abc, seqNum=1
16:03:11.914 [RpcThread-1] INFO org.example.testRpc.RpcManager -- [服务端]还有任务数量taskSize=0
16:03:11.914 [LogicThread] INFO org.example.testRpc.RpcManager -- [客户端]收到服务端的处理结果seqNum=1
16:03:11.915 [LogicThread] INFO org.example.testRpc.Main -- 得到返回:3
异常情况:
16:03:47.110 [LogicThread] INFO org.example.testRpc.RpcManager -- [客户端]发起rpc请求req=abc, reqNum=1
16:03:47.122 [RpcThread-1] INFO org.example.testRpc.RpcManager -- [服务端]开始处理请求seq=abc, seqNum=1, 还有任务数量taskSize=1
16:03:49.166 [RpcThread-1] INFO org.example.testRpc.RpcManager -- [服务端]处理请求完毕seq=abc, seqNum=1
16:03:49.172 [RpcThread-1] INFO org.example.testRpc.RpcManager -- [服务端]还有任务数量taskSize=0
16:03:49.173 [LogicThread] INFO org.example.testRpc.RpcManager -- [客户端]收到服务端的处理结果seqNum=1
16:03:49.173 [LogicThread] ERROR org.example.testRpc.RpcManager -- [客户端]判断出:返回类型错误!!! 请求类型=class java.lang.String, 期待服务端返回类型是class java.lang.Integer,实际返回类型是class java.lang.String
16:03:49.175 [LogicThread] INFO org.example.testRpc.Main -- rpc请求失败,reason=服务器返回类型错误!!!
*/