简体   繁体   English

Java ConcurrentHashMap和同步

[英]Java ConcurrentHashMap and synchronization

Let's say that I have a ConcurrentHashMap of clients registered to a server (inside a class Server): 假设我有一个ConcurrentHashMap客户注册到服务器(在类Server内):

Map<ClientID, String> registeredClients = new ConcurrentHashMap<ClientID, String>();

In my registration method (inside the Server class) I have: 在我的注册方法中(在Server类中),我有:

  public void synchronized register(ClientID client, String clientName) {
        if(!registeredClients.containsKey(client))
          registeredClients.put(client, clientName);
  }

And in any other methods of the server, I always check at the beginning that the client is registered (to be sure that he is eligible to use the method): 在服务器的任何其他方法中,我总是在开始时检查客户端是否已注册(以确保他有资格使用该方法):

if(!registeredClients.containsKey(client))
  throw new UnknownClientException();

I have one server thread per client. 每个客户端有一个服务器线程。

Have I to synchronize that check with something like this? 我是否需要将该支票与类似内容同步?

synchronized(registeredClients) {
  if(!registeredClients.containsKey(client))
    throw new UnknownClientException();
}

I think I should because theoretically the client could register after having passed the if guard and before throwing the exception (making the exception actually wrong). 我认为应该这样做,因为从理论上讲,客户端可以在通过if防护之后并引发异常之前注册(使异常实际上是错误的)。

I am not quite how much the ConcurrentHashMap helps programmers with synchronization issues. 我不太了解ConcurrentHashMap对程序员解决同步问题有多大帮助。

No you don't have to synchonize the containsKey api if the Class is ConcurrentHashMap because as stated in the documentation its operations are thread safe (You can read all the documentation in order to understand how concurrent access is managed). 不,如果Class为ConcurrentHashMap,则不必同步containsKey api,因为如文档中所述,其操作是线程安全的(您可以阅读所有文档以了解如何管理并发访问)。

I suggest you two modifications: 我建议您进行两个修改:

Change 更改

Map<ClientID, String> registeredClients = new ConcurrentHashMap<ClientID, String>();

to

ConcurrentMap<ClientID, String> registeredClients = new ConcurrentHashMap<ClientID, String>();

because you want explicitly manage concurrent access in you code 因为您要在代码中显式管理并发访问

After doing 1. you can use registeredClients.putifAbsent(client, clientName); 完成后1.您可以使用registeredClients.putifAbsent(client, clientName);

instead of 代替

  if(!registeredClients.containsKey(client))
          registeredClients.put(client, clientName);

and avoid the synchronized keyword in the method signature 并避免在方法签名中使用synchronized关键字

If you are using Java 8, you can check with the following code: 如果您使用的是Java 8,则可以使用以下代码进行检查:

registeredClients.computeIfAbsent(client, c -> {throw new UnknownClientException();});

The check if the key exists and the execution of the lambda are atomic. 检查密钥是否存在以及lambda的执行是原子的。 This requires UnknownClientException to be an unchecked exception. 这要求UnknownClientException是未经检查的异常。

For Java 7 I have no solution that is this simple. 对于Java 7,我没有这么简单的解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM