场景
线程间通信的一种方式,物联网服务端下发指令,有时不是http的方式走的是MQTT协议,这时服务端推送指令到设备回复就需要用异步转同步,将发指令,设备回复当做是一次调用
实现
采用 CountDownLatch 来做等待同步处理
目录结构
1、指令内容类
public class Message {
private String messageId;
private String payload;
public Message(String messageId, String payload) {
this.messageId = messageId;
this.payload = payload;
}
public String getMessageId() {
return messageId;
}
public void setMessageId(String messageId) {
this.messageId = messageId;
}
public String getPayload() {
return payload;
}
public void setPayload(String payload) {
this.payload = payload;
}
@Override
public String toString() {
return "Message{" +
"messageId='" + messageId + '\'' +
", payload='" + payload + '\'' +
'}';
}
}
2、异步转同步载体
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
public class SyncFuture<T>{
private final CountDownLatch latch = new CountDownLatch(1);
private T response;
public T get() throws InterruptedException {
latch.await();
return response;
}
// 重写获取
public T get(long timeout, TimeUnit unit) throws InterruptedException {
if (latch.await(timeout, unit)) {
return response;
}
return null;
}
// 填充
protected void set(T response) {
this.response = response;
latch.countDown();
}
}
3、异步转同步工具
import com.gyg.future.Message;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class SyncFutureUtil {
private static final Map<String, SyncFuture<Message>> futureMap = new ConcurrentHashMap<>();
public static SyncFuture<Message> createSyncFuture(String messageId){
SyncFuture<Message> future = new SyncFuture<>();
futureMap.put(messageId, future);
return future;
}
public static void setResponse(String messageId,Message message){
futureMap.computeIfPresent(messageId, (k, v) -> {v.set(message);return v;});
}
public static void remove(String messageId){
futureMap.remove(messageId);
}
}
4、测试类
import java.util.UUID;
import java.util.concurrent.TimeUnit;
public class Main {
public static void main(String[] args) throws InterruptedException {
String messageId = UUID.randomUUID().toString();
SyncFuture<Message> syncFuture = SyncFutureUtil.createSyncFuture(messageId);
// 3s 后 recover thread 回复
new Thread(()->{
System.out.println("处理指令 需要3s");
try {
TimeUnit.SECONDS.sleep(3L);
SyncFutureUtil.setResponse(messageId,new Message(messageId, "{\"status\":1}"));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
},"recover thread").start();
// 下发指令,main thread 等待回复
Message message = syncFuture.get(5L, TimeUnit.SECONDS);
System.out.println("收到回复 : "+message.toString());
}
}