简体   繁体   English

客户端/服务器多线程和ConcurrentHashMap-为什么没有将client.get(id)锁定?

[英]Client/server multithreading and ConcurrentHashMap - why isn't clients.get(id) being locked?

I have the following block of code in my server: 我的服务器中有以下代码块:

clients.putIfAbsent(id, new Integer(0));
synchronized (clients.get(id)) {
    if (o instanceof Integer) {
        x = new Integer(((Integer) o).intValue());
        value = clients.get(id); // existing value in HashMap
        value = new Integer(value.intValue() + x);
        clients.put(id, value);
    } else if (o instanceof String) {
        clients.put(id, new Integer(0));
    }
    Thread.sleep(SockServer5.sleepTime);
out.writeObject(clients.get(id));
    out.flush();
}

clients is a ConcurrentHashMap, while o is the object input being read from the client. clients是ConcurrentHashMap,而o是从客户端读取的对象输入。 For each new client connection, the server spawns a new thread. 对于每个新的客户端连接,服务器都会产生一个新线程。

I would like to know, is there any particular reason why my clients.get(id) isn't being locked? 我想知道,是否有任何特定原因导致我的clients.get(id)没有被锁定?

It is really hard to understand what you are trying to achieve, clients.get(id) returns an instance of an Object and you are synchronizing on it. 确实很难理解要实现的目标, clients.get(id)返回一个Object的实例,并且您正在对其进行同步。

Fine. 精细。

That does not prevent access to the concurrent hashmap by another thread. 这不会阻止其他线程访问并发哈希图。 I suspect you want to prevent access to the Hashmap, in which case you should use an Object() as a mutex 我怀疑您想阻止对Hashmap的访问,在这种情况下,您应该使用Object()作为互斥量

In both branches of your if statement, you are putting a new object into the map. if语句的两个分支中,您都将一个新对象放入映射中。 Therefore all other threads will find a different object as result of client.get(id). 因此,所有其他线程都将根据client.get(id)找到不同的对象。 Even if you have two equal integers in the map, they are not same objects. 即使映射中有两个相等的整数,它们也不是相同的对象。 Example: if 'o' is always a string, each execution of the code will replace the value in the map, and each following thread will get a new object in client.get() (well some may be lucky enough to get a previous object, but most will get a new one, since the synchronized block is rather small and fast comparing to stream handling and your sleep (because the object gets replaced, before the sleep finishes)). 例如:如果“ o”始终是一个字符串,则每次执行代码都会替换映射中的值,并且随后的每个线程都将在client.get()中获得一个新对象(有些可能很幸运,可以得到前一个对象,但大多数对象都会获得一个新对象,因为与流处理和您的睡眠相比,同步块非常小且速度较快(因为在睡眠完成之前,该对象已被替换)。

If you want to synchronize on a non-existing object, on the idea (or id) of the object, check out this github repo: https://github.com/anotheria/idbasedlock 如果要在不存在的对象,对象的概念(或ID)上进行同步,请查看以下github存储库: https : //github.com/anotheria/idbasedlock

Two things: first 两件事:第一

One shall not use new Integer but Integer.valueOf(i) 不得使用新的Integer,而应使用Integer.valueOf(i)

The other thing is that there isn't even a need to use synchronized. 另一件事是,甚至不需要使用同步。 It completely defies the reason to use a concurrent map, because it throttles down threads to single-threaded thanks to blocking. 它完全无视使用并发映射的原因,因为由于阻塞,它可以将线程限制为单线程。 Here is a solution that does not use synchronized but is still thread-safe: 这是一个不使用同步但仍然是线程安全的解决方案:

clients.putIfAbsent(id, Integer.valueOf(0));

Integer value;
do {
  value = clients.get(id);
} while (clients.replace(id, value, value + o) == false); // repeat until value did not change in between

Thread.sleep(SockServer5.sleepTime);
out.writeObject(value);
out.flush();

Where clients is defined as (replace String with whatever you use): clients定义为(将String替换为您使用的任何字符):

final ConcurrentHashMap<String, Integer> clients;

This uses the same concept as compareAndSet does in other Atomics: it repeats until no thread interfered in between. 它使用与compareASet在其他Atomics中相同的概念:重复进行直到直到线程之间没有干扰为止。 The big benefit is that no thread needs to be blocked, so on a multi-core machine all cores can be used at 100% all the time . 最大的好处是不需要阻塞任何线程,因此在一台多核计算机上,所有核都可以一直以100% 的速度使用

Please note as well the usage of automatic boxing of Integers in value + o . 请注意, value + o的自动装箱整数的用法。 Java will use the most efficient form here on its own. Java将自行使用最有效的形式。

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

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