3

我在java中有一个多客户端服务器应用程序。服务器继续接收连接,每个客户端由一个单独的线程处理。客户端/服务器通信一直持续到套接字关闭。因此,从客户端收到的请求被放入 LinkedBlockingQueue 中,然后其他线程处理来自该队列的每个请求。由于客户端请求已添加到队列中,因此我稍后在处理请求并准备好响应时使用 ConcurrentHashMap 获取客户端套接字,以便稍后将响应发送给客户端。

现在我需要实现一个超时功能,所以如果请求没有被处理并且响应在一段时间内没有准备好,那么会向客户端发送某种消息,表明您的请求现在无法处理。谁能告诉我在多线程环境中执行此操作的最佳方法。请记住,我有一个客户端映射,其中针对每个请求 ID 放置客户端连接。

我正在考虑有一个单独的线程来继续迭代地图键并检查时间。但是由于请求继续添加到地图中,我想要一些最好的方法来做到这一点。

谢谢

4

2 回答 2

2

Guava 的加载缓存可以为您解决超时和并发修改:https : //code.google.com/p/guava-libraries/wiki/CachesExplained 通过如下设置将您的请求映射交换为 LoadingCache:

LoadingCache<Request, Connection> requests = CacheBuilder.newBuilder()
       .maximumSize(1000)
       .expireAfterAccess(1, TimeUnit.MINUTES)
       .removalListener(MY_LISTENER)
       .build(
           new CacheLoader<Request, Connection>() {
             public Connection load(Request request) throws AnyException {
               return clientConnectionForRequest(request);
             }
           });

当一个请求进来时,你将它加载到缓存中:

requests.get(request);

在此之后,请求将坐在那里等待处理。如果开始处理,则获取连接并使请求无效,因此将其从缓存中删除。①</p>

Connection c = requests.getIfPresent(request);
if (c != null) {
  requests.invalidate(request); // remove from the waiting area
  // proceeed with processing the request
} else {
  // the request was evicted from the cache as it expired
}

在删除侦听器中,您需要实现一些简单的逻辑来侦听驱逐。(如果您明确地使无效,那么wasEvicted()将返回 false。)

MY_LISTENER = new RemovalListener<Request, Connection>() {
    @Override
    public void onRemovaRequest RemovalNotification<Request, Connection> notification) {
        if (notification.wasEvicted()) {
            Connection c = notification.getValue();
            // send timeout response to client 
        }
    }
};

您可以通过将请求放入队列并执行①中描述的方法来对请求进行排序,该方法还将负责仅执行那些尚未超时的请求,您不需要额外的内部维护。

于 2013-09-19T08:31:51.490 回答
1

使用并发哈希映射。它允许读取的完全并发和可调整的写入并发。它使用 volatile 变量来放置数据。即使任何线程正在对存储桶进行任何修改,尝试从同一存储桶读取数据的任何其他线程都可以看到它。

于 2013-09-19T08:03:49.467 回答