首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用ReadWriteLock?

如何使用ReadWriteLock?
EN

Stack Overflow用户
提问于 2009-10-29 20:38:52
回答 5查看 993关注 0票数 5

以下是我的情况。

在web应用程序启动时,我需要加载一个Map,然后由多个传入线程使用。也就是说,请求进入并使用Map来确定它是否包含特定的键,如果包含,则检索该值(对象)并将其与另一个对象关联。

现在,Map的内容有时会发生变化。我不想重新启动应用程序来重新加载新的情况。相反,我想动态地做这件事。

但是,在Map重新加载时(删除所有项目并将其替换为新项目),该Map上的并发读取请求仍会到达。

我应该怎么做,以防止所有读取线程访问该映射时,它正在被重新加载?我如何才能以最高性能的方式做到这一点,因为我只在Map重新加载时才需要它,而重新加载只会偶尔发生(每x周发生一次)?

如果上面不是一个选项(阻塞),我如何确保在重新加载我的读请求时不会遭受意外的异常(因为键不再存在,或者值不再存在或被重新加载)?

我得到的建议是,ReadWriteLock可能会帮助我解决问题。你能给我一个例子,告诉我应该如何在我的读者和作者之间使用这个ReadWriteLock吗?

谢谢,

E

EN

回答 5

Stack Overflow用户

发布于 2009-10-29 20:47:34

我建议按如下方式处理:

  1. 可在中心位置访问您的地图(可以是singleton、静态...)。
  2. 开始重新加载时,让实例按原样在不同的地图实例中工作。
  3. 填充新地图后,用新地图替换旧地图(这是一个原子操作)。

示例代码:

代码语言:javascript
复制
    static volatile Map<U, V> map = ....;

    // **************************

    Map<U, V> tempMap = new ...;
    load(tempMap);
    map = tempMap;

并发效果:

  • volatile帮助其他threads.
  • While查看变量的可见性,重新加载映射,所有其他线程都看到旧值未受干扰,因此它们不会受到任何损失whatsoever.
  • Any线程在映射更改之前检索映射的瞬间将使用旧值。
    • It可以向同一旧地图实例请求多个values.

,这非常有利于数据一致性(而不是从旧地图加载第一个值,从较新地图加载其他值)。

  • It将使用旧地图完成对其请求的处理,但下一个请求将再次请求地图,并将接收较新的get

票数 6
EN

Stack Overflow用户

发布于 2009-10-29 20:49:32

如果客户端线程不修改映射,即映射的内容仅依赖于从何处加载的源,则可以简单地加载新映射,并在加载新映射后替换对客户端线程正在使用的映射的引用。

除了在短时间内使用两倍的内存之外,不会产生性能损失。

如果映射使用的内存太多,无法拥有两个映射,您可以对映射中的每个对象使用相同的策略;迭代映射,构造一个新的映射到对象,并在对象加载后替换原始映射。

票数 3
EN

Stack Overflow用户

发布于 2009-10-29 20:59:14

请注意,如果您依赖于映射在一段时间内保持不变,那么按照其他人的建议更改引用可能会导致问题(例如if (map.contains(key)) {V value = map.get(key); ...}。如果需要,您应该保留对地图的本地引用:

代码语言:javascript
复制
static Map<U,V> map = ...;

void do() {
  Map<U,V> local = map;
  if (local.contains(key)) {
    V value = local.get(key);
    ...
  }
}

编辑:

假设您不想让客户端线程进行代价高昂的同步。作为一种权衡,您允许客户端线程完成它们在地图更改之前就已经开始的工作-忽略地图运行时发生的任何更改。这样,您可以安全地对映射做出一些假设-例如,键存在,并且在单个请求的持续时间内始终映射到相同的值。在上面的示例中,如果您的读取器线程在调用map.contains(key)的客户端之后更改了地图,则客户端可能会在map.get(key)上得到null -并且几乎可以肯定的是,您将以NullPointerException结束此请求。因此,如果您对map进行多次读取,并且需要像前面提到的那样做一些假设,则最简单的方法是保留对map (可能已过时)的本地引用。

在这里,volatile关键字并不是必须的。只要您更改了引用(map = newMap),就可以确保新的映射被其他线程使用。如果没有易失性,后续的读取(local = map)仍然可以在一段时间内返回旧的引用(虽然我们谈论的是少于一纳秒的时间)--如果我没记错的话,尤其是在多核系统上。我不会关心它,但如果你觉得需要额外的多线程之美,你当然可以自由使用它;)

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1643428

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档