当插入/删除由其他线程在地图上进行时迭代地图键

时间:2013-09-19 07:45:33

标签: java multithreading

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

现在我需要实现超时功能,因此如果请求不是进程并且响应在一段时间内没有准备好,那么会向客户端发送某种消息,表明您的请求现在无法处理。任何人都可以告诉我在多线程环境中做到这一点的最佳想法。请记住,我有一个客户端映射,其中客户端连接针对每个请求ID。

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

由于

2 个答案:

答案 0 :(得分: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);

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

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 
        }
    }
};

您可以通过将请求放入队列并执行①中描述的方法来对请求进行排序。该方法还将仅处理那些没有超时的请求,您不需要额外的管家。

答案 1 :(得分:1)

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