当前位置: 首页 > 知识库问答 >
问题:

并发哈希表作为带同步的singletone缓存

海保臣
2023-03-14

您认为,我们需要使用同步块来更好地优化对广告实例的访问吗?Ad.class的实例可以从不同的线程中检索。Synchronized有助于通过ConcurrentHashMap中的一个get操作一次性获取实例。ConcurrentHashMap将所有值存储为易失性。我在android的java 1.7上使用它,computeIf Absent在java 1.8中可用。

如果能得到详细的答案,为什么不可以或者为什么可以,那就太好了。谢谢大家!

public final class Ad {

    private final static Map<String, Ad> ads = new ConcurrentHashMap<>();

    public static Ad get(@NonNull String appId) {
        if (appId == null) appId = "";

        boolean containsAd = ads.containsKey(appId);

        Ad localInstance = containsAd ? ads.get(appId) : null;

        if (localInstance == null) {
            synchronized (Ad.class) {

                containsAd = ads.containsKey(appId);

                localInstance = containsAd ? ads.get(appId) : null;

                if (localInstance == null) {
                    localInstance = new Ad();
                    localInstance.setAdId(appId);
                    ads.put(appId, localInstance);
                }
            }
        }
        return localInstance;
    }

    private Ad() {
    }
}

更新:感谢所有人的帮助。我将ConcurrentHashMap替换为HashMap。

共有2个答案

咸利
2023-03-14

据我了解,您实际想要实现的是 putIfAbsent,因此这比您所做的要简单得多(您正在使用双重检查锁定):

public static Ad get(String appId) {
    String newId = appId == null ? "" : appId;
    ads.putIfAbsent(newId, new Ad());
    return map.get(newId);
}
麹正业
2023-03-14

这不是一个理想的选择。如果多个线程尝试同时初始化值,那么即使它们正在寻找不同的键,它们也会相互阻塞。

您应该使用 ConcurrentHashMap.computeIfAbsent 来检查添加并在一个步骤中创建缺失的添加。这样,您就不会创建任何未使用的广告,并且两个线程只会在尝试初始化同一条目时相互阻止:

public static Ad get(@NonNull String appId) {
    if (appId == null) appId = "";

    return ads.computeIfAbsent(appId, Ad::new);
}

private Ad(String appId) {
    this();
    setAdId(appId);
}
 类似资料:
  • 本文向大家介绍Java中并发哈希映射和同步哈希映射之间的区别,包括了Java中并发哈希映射和同步哈希映射之间的区别的使用技巧和注意事项,需要的朋友参考一下 并发Hashmap是jdk1.5中引入的类。并发哈希映射仅在添加或更新映射时在称为片段的存储桶级别应用锁。因此,并发哈希映射允许对映射进行并发读写操作。  同步hashmap(Collection.syncronizedHashMap())是C

  • 问题内容: 我有一个实现了hashCode()的向量类。它不是我写的,而是使用2个质数对2个向量分量进行异或运算。这里是: …因为这是来自已建立的Java库,所以我知道它可以正常工作。 然后,我有一个Boundary类,其中包含2个向量:“开始”和“结束”(代表直线的端点)。这两个向量的值是边界的特征。 在这里,我尝试为构成该边界的向量的唯一2元组(起点和终点)创建一个良好的hashCode()。

  • 问题内容: 当大小超过maxthreshold值时,如何在哈希表或哈希表中进行重新哈希处理? 是否所有对都已复制到新的存储桶阵列中? 编辑: 重新哈希后,同一存储桶(位于链接列表中)中的元素会发生什么情况?我的意思是说,他们在重新哈希处理后会留在同一个桶中吗? 问题答案: 问题中的最大阈值称为负载系数。 建议负载系数约为0.75。负载因子定义为(m / n),其中n是哈希表的总大小,m是在需要增加

  • 哈希表 通过最简单的取模运算作为哈希算法 class HashNode(object): def __init__(self, id, data): self.id = id self.data = data self.next = None def __str__(self): return '(%d,%s)' %

  • REDIS_HASH (哈希表)是 HSET 、 HLEN 等命令的操作对象, 它使用 REDIS_ENCODING_ZIPLIST 和 REDIS_ENCODING_HT 两种编码方式: 字典编码的哈希表 当哈希表使用字典编码时, 程序将哈希表的键(key)保存为字典的键, 将哈希表的值(value)保存为字典的值。 哈希表所使用的字典的键和值都是字符串对象。 下图展示了一个包含三个键值对的哈希

  • Hashtbl 模块 Hashtbl模块实现了一个高效的,可变的查询表。如下创建一个哈希表: # let my_hash = Hashtbl.create 123456;; val my_hash : ('_weak1, '_weak2) Hashtbl.t = <abstr> 这个123456是哈希表的初始大小。这个值可以是你对数据量的一种猜测,但是哈希表有可能会 随着数据量的增多而变大,因此