我的服务器中有以下代码块:
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)
没有被锁定是否有任何特殊原因?
答案 0 :(得分:0)
很难理解你想要实现的目标,clients.get(id)
返回一个Object的实例并且你正在同步它。
精细。
这不会阻止另一个线程访问并发hashmap。我怀疑你想阻止访问Hashmap,在这种情况下你应该使用Object()作为互斥体
答案 1 :(得分:0)
在 if 语句的两个分支中,您将新对象放入地图中。因此,所有其他线程将找到client.get(id)的结果的不同对象。即使地图中有两个相等的整数,它们也不是同一个对象。 示例:如果'o'始终是一个字符串,则每次执行代码都将替换map中的值,并且每个后续线程将在client.get()中获取一个新对象(有些人可能很幸运能够得到一个对象,但大多数会得到一个新的,因为与流处理和你的睡眠相比,synchronized块相当小而且快(因为在睡眠结束之前对象被替换))。
如果你想在一个不存在的对象上同步对象的想法(或id),请查看这个github repo:https://github.com/anotheria/idbasedlock
答案 2 :(得分:0)
两件事:第一件事
不能使用新的整数但Integer.valueOf(i)
另一件事是甚至不需要使用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();
将clients
定义为(用您使用的任何内容替换String):
final ConcurrentHashMap<String, Integer> clients;
这与其他Atomics中的compareAndSet使用相同的概念:它重复直到没有线程干扰。最大的好处是不需要阻塞任何线程,因此在多核机器上,所有核心都可以100%一直使用。
请注意value + o
中自动装箱整数的用法。 Java将自己使用最有效的表单。