java - 正确调用 Hashmap 的 get() 和 put() 方法。

标签 java multithreading concurrency hashmap

对于下面的代码:

public ReentrantReadWriteLock getLock(String tableName) {
    ReentrantReadWriteLock lock = locksMap.get(tableName);
    if (lock == null) {
        lock = new ReentrantReadWriteLock();
        locksMap.put(tableName, lock);
    }
}

//其中locksMap是一个HashMap,键为String(tableName),值为ReentrantReadWriteLock(Lock)。

我的问题是,如果线程同时访问这个方法,他们会得到具有相同“tableName”的不同Lock对象,因为Map的get和put方法是分开调用的。

任何带有解释的解决方案将不胜感激? 提前致谢。

最佳答案

使用 ConcurrentMap 通常会产生比 synchronized block 更好的性能。

Java 5-7:

ConcurrentMap<String, ReadWriteLock> lockMap = new ConcurrentHashMap<>();

ReadWriteLock getLock(String key) {
    ReadWriteLock lock = lockMap.get(key);
    if (lock == null) {
        lock = new ReentrantReadWriteLock();
        ReadWriteLock other = lockMap.putIfAbsent(key, lock);
        if (other != null) {
            // another thread's putIfAbsent won
            lock = other;
        }
    }
    return lock;
}

Java 8+:

ConcurrentMap<String, ReadWriteLock> lockMap = new ConcurrentHashMap<>();

ReadWriteLock getLock(String key) {
    return lockMap.computeIfAbsent(key, ReentrantReadWriteLock::new);
}

首先,ConcurrentHashMap 之类的实现被记录为不在读取 操作上使用锁。因此,在这种情况下,您打算为单个 key 获取锁的次数似乎比您打算创建新锁的次数要多得多,这将减少线程争用。如果您使用了 synchronized,即使已经创建了锁,您也会强制每个线程通过临界区处理单个文件。

此外,实现可以执行更高级的锁定形式,甚至是分片 锁定,这样两个编写器就不必互相阻塞(如果写入底层数据结构的不同分区)。同样,synchronized 使用单个监视器对象,无法从了解底层数据结构的细节中获益。

由于 lambda 和函数引用,Java 8 版本变成了单行代码。 ::new 语法引用相邻的 ReentrantReadWriteLock 类的公共(public)、无参数构造函数。 computeIfAbsent 方法只会在必要时调用该构造函数,并且基本上会为您完成上面 Java 7 版本中的所有样板文件。如果创建新对象的成本很高或有不幸的副作用,这将特别有用。请注意,Java 7 版本必须在某些情况下创建新的锁实例,并且新对象可能不会被使用/返回。

关于java - 正确调用 Hashmap 的 get() 和 put() 方法。,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27113045/

相关文章:

java - 使用 A* 在图中寻找路径

c++ - 多线程环境中的信号处理函数

java - 即使正在释放许可证,Semaphore 类也会陷入僵局吗?

java - 哪里需要同步?

mysql - 并发 mySql 数据库查询

java - 按计划在 AWS EC2 实例上重启 Tomcat 服务

java - 错误 :Execution failed for task ':app:transformClassesAndResourcesWithProguardForDebug'

C++ pthread - 如何取消线程?

MySQL 服务器仅使用 48 个 CPU 内核中的 1 个进行 GROUP BY 查询

java - 搞乱 JPA 并收到错误创建用户 - 无法设置字段值