Java 客户机/服务器多线程和ConcurrentHashMap-为什么是isn';t客户端。是否锁定(id)?
我的服务器中有以下代码块:Java 客户机/服务器多线程和ConcurrentHashMap-为什么是isn';t客户端。是否锁定(id)?,java,multithreading,synchronized,concurrenthashmap,Java,Multithreading,Synchronized,Concurrenthashmap,我的服务器中有以下代码块: 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 = n
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
是ConcurrentHashMap,而o
是从客户端读取的对象输入。对于每个新的客户端连接,服务器都会生成一个新线程
我想知道,我的
clients.get(id)
没有被锁定有什么特殊原因吗?很难理解你想要实现什么,clients.get(id)
返回一个对象的实例,你正在同步它
好的
这不会阻止另一个线程访问并发hashmap。我怀疑您想阻止对Hashmap的访问,在这种情况下,您应该在if语句的两个分支中使用Object()作为互斥对象,因为您正在将一个新对象放入映射中。因此,作为client.get(id)的结果,所有其他线程将找到一个不同的对象。即使贴图中有两个相等的整数,它们也不是相同的对象。
示例:如果“o”始终是一个字符串,则每次执行代码都会替换映射中的值,接下来的每个线程都会在client.get()中获得一个新对象(有些线程可能很幸运地获得了上一个对象,但大多数线程都会获得一个新对象,因为与流处理和睡眠相比,同步块非常小且速度很快(因为对象在睡眠结束之前被替换)
如果您想在一个不存在的对象上,在对象的想法(或id)上进行同步,请查看这个github repo:两件事:第一件事
不应使用新整数,而应使用新整数
另一件事是,甚至不需要使用synchronized。它完全违背了使用并发映射的理由,因为它通过阻塞将线程限制为单线程。下面是一个不使用synchronized但仍然是线程安全的解决方案:
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();
其中,客户机
定义为(将字符串替换为您使用的内容):
最终ConcurrentHashMap客户端;
这使用了与其他原子中相同的概念:它会重复,直到线程之间没有干扰。最大的好处是不需要阻塞线程,因此在多核机器上,所有内核都可以始终以100%的速度使用
请注意在
value+o
中自动装箱整数的用法。Java将自己使用最有效的形式。每个调用线程可能在不同的对象上同步,因为“id”将具有不同的值,因此返回不同的对象。您应该只在同一个对象上同步。我的测试使用单个id轰炸我的服务器,然后使用两个,然后是三个,然后是10个,每个id总共进行100个连接。每次id数增加一倍,所需时间应该是前一次的一半。我已经测试过这个,这显然没有发生。你有一个客户。获取(id)它将返回0或另一个int值,并且您正在锁定此整数值。不确定您打算从中获得什么,但它不会锁定影响同步块内代码的任何内容。很难理解您试图实现什么,cleints.get(id)
返回一个对象的实例,您正在该实例上进行同步。很好。这不会阻止另一个线程访问并发hashmap。我怀疑您想阻止访问hashmap,您应该在其中使用Object()作为互斥体。
final ConcurrentHashMap<String, Integer> clients;