Java如何在将来获取地图值?

时间:2017-06-30 03:39:54

标签: java multithreading

这里的伪代码:

//-- Thread A
sender.send(requestId, request);
// Wait receiver to receive response for that requestId
return requestIdToResponseMap.get(requestId);


//--- Thread B
response = receiver.receive();
requestIdToResponseMap.put(response.requestId, response);

注意: 对下游服务的调用是:

  1. 耗时
  2. 异步(即请求的响应只能通过 request-id 进行映射)
  3. 让我们说下游服务是一个websocket客户端。服务器发送消息并等待响应。

    关于 requestIdToResponseMap ,我尝试了3个解决方案:

    1. 使用requestIdToLockMap来保存锁,并使用requestIdToResponseMap来保存响应值,但这似乎很复杂。
    2. 使用地图<字符串,可选<响应>>,但是Optional是不可变的,我无法更改其值。这不起作用。
    3. 使用地图<字符串,对<锁定,响应>&gt ;,接收方通知相应的锁定,然后通知发送方线程并检索该值。
    4. 那么,对于这类问题,通常的解决方案是什么?

2 个答案:

答案 0 :(得分:0)

您没有详细说明您的使用案例,因此我一般会回答这个问题:

Java有多个framework用于多线程消费者 - 生产者案例。如果你发现自己正在考虑锁和线程原语,你可能会重新发明轮子。专注于重要的事情:-)

这是一个让你入门的片段:

 // create your thread pool, threads here will consume your "requests"
 ExecutorService threadPool = Executors.newFixedThreadPool(1);
 // submit a request to the pool. This gets enqueued on a queue, until it is picked up by a thread. Returns a future- a reference to the uncompleted work
 Future<Response> future = threadPool.submit(new RequestTask<Response>(request, requestId));
 // wait for the work to complete
 Response response = future.get();

您的RequestTask实施Callable

   private static class RequestTask implements Callable<Response> {
        @Override
        public Response call() throws Exception {
            ...
        }
    }

为了清楚起见,你的制作人主题是&#34;主要&#34;线程(在您的示例中为A),而使用者位于线程池(线程B)中。您可以增加线程池大小(在一定程度上)以增加请求吞吐量。

有大量关于Java的ExecutorService和生产者 - 消费者模式的引用。请记住,在生产者和消费者线程之间有一个队列,因为您可以生成比您可以使用的更快的请求。它默认无限制,非常重要的是要记住它!

如果您还有其他问题,请告诉我们。

答案 1 :(得分:0)

创建将存储reponsefuture的地图,如果结果不可用将阻塞,线程将等待。您可以使用其他功能进行修改,例如等待多长时间。

private static ConcurrentHashMap<String, ExecutorSeriveInstanceFuture> instanceMap = new ConcurrentHashMap<String, ExecutorSeriveInstanceFuture>();

自定义Future,以便您可以根据用例进行修改。

private static class ExecutorSeriveInstanceFuture {
        private DBExecutorSerive dbExecutorSerive;
        private Throwable throwable;
        private Object lock = new Object();

        public DBExecutorSerive get() {
            if (dbExecutorSerive == null) {
                return dbExecutorSerive;
            }
            boolean restoreInterrupt = false;
            synchronized (lock) {
                while (dbExecutorSerive == null && throwable == null) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        restoreInterrupt = true;
                    }
                }

            }
            if (restoreInterrupt) {
                Thread.currentThread().interrupt();
            }
            if (dbExecutorSerive != null) {
                return dbExecutorSerive;
            }
            throw new IllegalStateException(throwable);
        }

        public void set(DBExecutorSerive dbExecutorSerive) {
            synchronized (lock) {
                this.dbExecutorSerive = dbExecutorSerive;
                lock.notifyAll();
            }
        }

        public void setFailure(Throwable throwable) {
            synchronized (lock) {
                this.throwable = throwable;
                lock.notifyAll();
            }
        }
    }