我目前正在深入研究 java 11 Properties 类的实现。在 java 11 源代码中,Properties 类将其数据存储在名为“map”的 ConcurrentHashMap 字段中。当您调用 Properties 的 setProperty 方法时,它实际上会调用其内部 ConcurrentHashMap 的 put 方法。我知道 ConcurrentHashMap 是一个线程安全的集合,所以我真的不明白为什么 setProperty 方法必须同步(如果 ConcurrentHashMap 已经同步)。 setProperty 方法的同步并没有消除使用 ConcurrentHashMap 的意义。我的意思是 Properties 类的用户必须等待锁定 setProperty 方法,该方法已经使用具有自己的同步的并发集合。
public class Properties extends Hashtable<Object,Object> {
/**
* use serialVersionUID from JDK 1.1.X for interoperability
*/
private static final long serialVersionUID = 4112578634029874840L;
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
/**
* A property list that contains default values for any keys not
* found in this property list.
*
* @serial
*/
protected volatile Properties defaults;
/**
* Properties does not store values in its inherited Hashtable, but instead
* in an internal ConcurrentHashMap. Synchronization is omitted from
* simple read operations. Writes and bulk operations remain synchronized,
* as in Hashtable.
*/
private transient volatile ConcurrentHashMap<Object, Object> map;
public synchronized Object setProperty(String key, String value) {
return put(key, value);
}
@Override
public synchronized Object put(Object key, Object value) {
return map.put(key, value);
}
请注意,这不是 Properties 的完整源代码。完整的实现可以在这里找到:https://github.com/AdoptOpenJDK/openjdk-jdk11/blob/master/src/java.base/share/classes/java/util/Properties.java
这是因为向后兼容。在 Java 8 中,
Properties
尚未委托给 ConcurrentHashMap
,而是依赖于它扩展 Hashtable
。那使用了同步方法,因此Properties
也是如此。这有一个很大的影响——锁定可以在外部使用。例如,使用带有 Properties
实例作为锁的同步块,并在其中执行各种操作。
如果现有方法不再同步,则可以在此类同步块之外更新
Properties
实例,这可能会破坏现有代码。