Java ConcurrentHashMap和同步

Java ConcurrentHashMap和同步,java,multithreading,synchronization,race-condition,concurrenthashmap,Java,Multithreading,Synchronization,Race Condition,Concurrenthashmap,假设我有一个注册到服务器(在类服务器内部)的客户机的ConcurrentHashMap: 在服务器的任何其他方法中,我总是在开始时检查客户机是否已注册(以确保他有资格使用该方法): 我每个客户端有一个服务器线程 我必须把支票和这样的东西同步吗 synchronized(registeredClients) { if(!registeredClients.containsKey(client)) throw new UnknownClientException(); } 我认为我应该

假设我有一个注册到服务器(在类服务器内部)的客户机的
ConcurrentHashMap

在服务器的任何其他方法中,我总是在开始时检查客户机是否已注册(以确保他有资格使用该方法):

我每个客户端有一个服务器线程

我必须把支票和这样的东西同步吗

synchronized(registeredClients) {
  if(!registeredClients.containsKey(client))
    throw new UnknownClientException();
}
我认为我应该这样做,因为理论上,客户机可以在通过if保护之后,在抛出异常之前进行注册(使异常实际上是错误的)


我不太清楚
ConcurrentHashMap
在多大程度上帮助程序员解决同步问题。

如果您使用的是Java 8,可以使用以下代码进行检查:

registeredClients.computeIfAbsent(client, c -> {throw new UnknownClientException();});
检查密钥是否存在以及lambda的执行是否是原子的。 这要求UnknownClientException是未检查的异常


对于Java 7,我没有这么简单的解决方案。

不,如果类是ConcurrentHashMap,那么您不必同步containsKey api,因为如中所述,它的操作是线程安全的(您可以阅读所有文档以了解如何管理并发访问)

我建议您进行两项修改:

改变

Map registeredClients=new ConcurrentHashMap()

ConcurrentMap RegisteredClient=new ConcurrentHashMap()

因为您希望在代码中显式管理并发访问

做完1。您可以使用
registeredClients.putifAbsent(client,clientName)

而不是

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

并且避免方法签名中的
synchronized
关键字

对于
register
方法有一个简单的解决方案,但对于其余的方法则没有。putIfAbsent()?我在想,但我认为在幕后它也做了类似的事情。我更关心的是“支票”问题。我想我必须同步多个“线程安全操作”。如果另一个线程在同步块退出后立即注销客户端会发生什么情况?您特别想解决哪些同步问题?您可以使用
remove
检查密钥是否存在,如果存在,只需再次
put
。不知道是否应该..注意:这并不比
String name=registeredClients.get(client)好多少;如果(name==null)抛出新的UnknownClientException()(如果您没有在表中存储任何空名称),或者(!registeredClients.containsKey(client))抛出新的UnknownClientException()(如果不需要实际获取客户端名称)。错误。您使用两条语句来检索名称并检查它,因此仍然存在Kami希望避免的竞争条件。我编写的代码使用ConcurrentHashMap的ComputeFabSent方法——这就是我们在这里讨论的内容——该方法的Javadoc声明:整个方法调用是以原子方式执行的,因此每个键最多应用一次函数。是的。但是,原子化地执行该操作并不会给您带来任何好处,因为在您的原子调用完成(并引发异常)之后,客户机仍然可以注册。最终结果是一样的:客户机已注册,但您抛出了一个异常。
synchronized(registeredClients) {
  if(!registeredClients.containsKey(client))
    throw new UnknownClientException();
}
registeredClients.computeIfAbsent(client, c -> {throw new UnknownClientException();});
  if(!registeredClients.containsKey(client))
          registeredClients.put(client, clientName);