这几天遇到了一个稍显特殊的场景,主要提供能力给外部接口,大概如下
逻辑大概如下:
1 外部调用服务端接口,服务端发送指令到设备端
2 服务端等待,设备端处理完返回接口到服务端,服务端返回结果给外部接口
所以,看到这里,这个时候由外部接口注册回调是最合适的,但是因为对方业务,不能这么做.所以考虑使用ReentrantLock.
综合设计如下:
接口参数携带唯一值,服务端根据唯一值生成ReentrantLock,由该次请求产生的ReentrantLock对象,生成对应的condition即可.
/**
* key 为orderId
*/
private static Map<String, AwtReceiveSignRequest> requestMap = new ConcurrentHashMap<>(16);
private final ConcurrentHashMap<String, ReentrantLock> locks = new ConcurrentHashMap<>(16);
private final ConcurrentHashMap<ReentrantLock, Condition> conditions = new ConcurrentHashMap<>(16);
@Override
public AwtSendSignResponse sendSignToDevice(AwtSendSignRequest request) {
AwtSendSignResponse response = null;
ReentrantLock lock = getLockForKey(request.getOrderId());
Condition condition = getConditionForLock(lock);
lock.lock();
try {
/**
业务逻辑处理
*/
/*
等待结果返回,或超时就返回
*/
boolean await = condition.await(20, TimeUnit.SECONDS);
AwtReceiveSignRequest receiveSignRequest = requestMap.get(request.getOrderId());
response = new AwtSendSignResponse();
} catch (Exception e) {
log.info("receive sign error :{}", e.getMessage());
return response;
} finally {
lock.unlock();
requestMap.remove(request.getOrderId());
locks.remove(request.getOrderId());
conditions.remove(lock);
}
return response;
}
//接受返回消息,接收到就放开阻塞
@Override
public void receiveMessage(AwtReceiveSignRequest request) {
log.info("received device callBack msg :{}", JsonUtils.toJson(request));
ReentrantLock lock = getLockForKey(request.getOrderId());
Condition condition = getConditionForLock(lock);
lock.lock();
try {
requestMap.put(request.getOrderId(), request);
condition.signalAll();
} catch (Exception e) {
log.info("receive msg fail ,cause ", e.getMessage());
} finally {
lock.unlock();
}
}
private ReentrantLock getLockForKey(String key) {
ReentrantLock lock = new ReentrantLock();
ReentrantLock previous = (ReentrantLock) this.locks.putIfAbsent(key, lock);
return previous == null ? lock : previous;
}
private Condition getConditionForLock(ReentrantLock lock) {
Condition condition = lock.newCondition();
Condition previous = (Condition) this.conditions.putIfAbsent(lock, condition);
return previous == null ? condition : previous;
}
以上为大概逻辑,目前是可以处理这种业务场景.