Вы можете использовать ConcurrentHashMap
(см. здесь ), который отображает строки маршрута, такие как "/api/user/1"
, в List
обратных вызовов, принимающих один параметр типа T
(замените T
накакой класс вы используете для хранения результатов запроса).Ваш метод request
должен будет использовать Consumer<T>
для обратного вызова.Если вы не знакомы с Consumer<T>
, вы можете прочитать об этом здесь .Это просто интерфейс, представляющий функцию, которая принимает один параметр типа T
и ничего не возвращает.
Когда поток хочет получить результат запроса к маршруту, он должен вызвать синхронизированный метод register
, которыйпринимает маршрут как String
и обратный вызов и выполняет следующее:
Следует проверить, является ли маршрут ключом в Map
.Если это не так, он должен добавить маршрут в качестве ключа к Map
со значением, равным List
, содержащим одно значение, обратный вызов, предоставленный в параметре, и затем он должен инициировать запрос с обратным вызовом кметод resolve
, о котором я расскажу ниже.Если маршрут уже был ключом в Map
, то обратный вызов потока должен быть просто добавлен к List
в Map
, где маршрут является ключом.
Функция resolve
должен принять маршрут как String
и результат запроса типа T
.Затем он должен получить List
в ключе маршрута, удалить ключ маршрута из Map
, и, наконец, перебрать все обратные вызовы и вызвать их с результатом запроса.
Я написал некоторый кодс примером, но я не проверял его.
CallbackHandler.java
public abstract class CallbackHandler<T> {
private QueryRepetitionHandler<T> handler;
private CountDownLatch latch;
private T result;
public CallbackHandler(QueryRepetitionHandler<T> handler) {
this.handler = handler;
latch = new CountDownLatch(1);
}
public void resolve(T result) {
this.result = result;
latch.countDown();
}
public void request(String route) {
handler.register(route);
latch.await();
}
}
QueryRepetitionHandler.java
public abstract class QueryRepetitionHandler<T> {
private Map<String, List<CallbackHandler<T>> map = new ConcurrentHashMap<>();
protected abstract void request(String route, Consumer<T> consumer);
public synchronized void register(String route, CallbackHandler<T> handler) {
if (map.containsKey(route)) {
map.get(route).add(callback);
} else {
List<CallbackHandler<T>> list = new ArrayList<>();
list.add(callback);
map.put(route, list);
request(route, result -> resolve(route, result));
}
}
private void resolve(String route, T result) {
List<Consumer<T>> list = map.remove(route);
// Sanity check
if (list != null) {
list.forEach(handler -> handler.resolve(result));
}
}
}
Вы хотите создать один экземпляр QueryRepetitionHandler<T>
чтобы быть доступным для всех ваших тем.Когда поток хочет сделать запрос, он должен создать экземпляр CallbackHandler<T>
, используя общий QueryRepetitionHandler<T>
.Конечно, вы не можете создать экземпляр QueryRepetitionHandler<T>
без реализации метода request
.Метод request
должен просто сделать запрос и затем вызвать обратный вызов, предоставленный как Consumer<T>
.Затем следует вызвать request
метод CallbackHandler<T>
с желаемым маршрутом в качестве аргумента String
.Затем этот поток будет ожидать (используя latch.await()
) результата запроса, пока QueryRepetitionHandler<T>
не вызовет свой метод resolve
с результатом и не вызовет latch.countDown()
.