0

Oracle的 ReadWriteLock javadoc及其实现描述了锁的作用以及如何使用它,但没有说明是否使用volatile关键字。

这与do-all-mutable-variables-need-to-be-volatile-when-using-locks不是同一个问题,因为我很高兴锁将正确同步访问和可见性,但volatile用于变量仍然是一个好主意,例如用于编译器优化或任何其他原因?

我的缓存数据由一个很少更改的List和几个Maps使用对象的各种属性映射列表中的对象组成。

private void reload() {
    Set<Registration> newBeans = dao.listRegistered();
    beans = Collections.unmodifiableSet(newBeans);
    codeToBeanMap.clear();
    userToBeanMap.clear();
    nameToBeanMap.clear();
    idToBeanMap.clear();
    for (Registration bean : newBeans) {
        codeToBeanMap.put(bean.getCode(), bean);
        userToBeanMap.put(bean.getUser(), bean);
        nameToBeanMap.put(bean.getName(), bean);
        idToBeanMap.put(bean.getId(), bean);
    }
}

最好的声明是什么?我有这个:

private Set<Registration> ecns;
private final Map<String, Registration> codeToBeanMap =
        new HashMap<String, Registration>();
private final Map<String, Registration> userToBeanMap =
        new HashMap<String, Registration>();
private final Map<String, Registration> nameToBeanMap =
        new HashMap<String, Registration>();
private final Map<String, Registration> idToBeanMap =
        new HashMap<String, Registration>();
4

3 回答 3

1

如果您要专门从受锁保护的代码中访问变量,那么指定该变量是多余的,volatile并且会导致一定的性能损失(它在纳秒范围内)。

于 2015-02-03T11:14:23.967 回答
1

你这样的声明对于并发来说很好:

private final Map<String, Registration> idToBeanMap = new HashMap<>();

...因为 Java 保证声明 final 的字段将在其他线程可以访问它们之前被初始化(至少 Java 1.5 起)。不需要 volatile 关键字(无论如何对 final 没有意义)。

但是,这并没有说明 HashMap 的内容——这不是线程安全的,不同的线程可能会看到不同或不一致的内容,除非您使用同步代码块。您最简单的解决方案是改用 ConcurrentHashMap 。这将保证所有线程都会看到预期的地图内容。

然而,这只意味着地图上的操作将是原子的。在您上面的代码中,您可能已经清除了一个地图,但没有清除其他地图(例如),此时另一个线程尝试读取可能给出不一致结果的数据。

所以,因为看起来你的代码需要多个 Map 来保持同步和相互一致,唯一的方法是使你的 reload 方法同步,并让客户端通过同一个对象上的同步方法来读取数据。

于 2015-02-03T11:19:18.220 回答
0

但是对变量使用 volatile 仍然是一个好主意,例如用于编译器优化或任何其他原因?

如果有任何 volatile 阻止编译器优化而不是启用它们。

Oracle 的 ReadWriteLock javadoc 及其实现描述了锁的作用以及如何使用它,但没有说明是否使用 volatile 关键字。

确实如此,事实上,如果您查看读写锁实现的接口,特别是Lock 接口 声明实现必须提供与块相同的内存可见性保证synchronized()

所有 Lock 实现必须强制执行与内置监视器锁提供的相同内存同步语义,如 The Java™ Language Specification 的第 17.4 节所述:

  • 成功的锁定操作与成功的锁定操作具有相同的内存同步效果。
  • 成功的解锁操作与成功的解锁操作具有相同的内存同步效果。
于 2015-02-03T11:16:53.387 回答