互斥与对象问题

Mutex vs object issue

我正在查看 Collections.synhronizedMap() 的 java 代码。我发现它在 implementation.Now 以下,我的问题是 1) 为什么我们使用同步(互斥) 2) 如果我们使用 synchronized(m)

会怎样

我的理解是,如果我们执行 synchronized(m),那么也只有一个线程能够访问映射。

static class SynchronizedMap<K, V> implements Map<K, V>, Serializable {
    private static final long serialVersionUID = 1978198479659022715L;

    private final Map<K, V> m;

    final Object mutex;

    SynchronizedMap(Map<K, V> map) {
        m = map;
        mutex = this;
    }

    SynchronizedMap(Map<K, V> map, Object mutex) {
        m = map;
        this.mutex = mutex;
    }

    public void clear() {
        synchronized (mutex) {
            m.clear();
        }
    }

    public boolean containsKey(Object key) {
        synchronized (mutex) {
            return m.containsKey(key);
        }
    }

    public boolean containsValue(Object value) {
        synchronized (mutex) {
            return m.containsValue(value);
        }
    }

    public Set<Map.Entry<K, V>> entrySet() {
        synchronized (mutex) {
            return new SynchronizedSet<Map.Entry<K, V>>(m.entrySet(), mutex);
        }
    }

    @Override
    public boolean equals(Object object) {
        synchronized (mutex) {
            return m.equals(object);
        }
    }

编辑:我想要一些与这个问题相关的说明

1) Java 的 this 关键字用于引用使用它的方法的当前实例。因此,如果我将互斥量放在这个关键字上,那么这是否意味着我们将锁定对象的当前实例或者我们将锁定线程的当前实例?如果有人能更全面地解释以下语句的含义,我将不胜感激

mutex = this;

在任何一种情况下,一次只有一个线程可以访问地图内容。

将互斥锁与地图分开是更好的风格。如果传入的映射有其他线程在其上同步,则不会影响此对象。将锁与映射分开可以让用户单独指定锁,因此它允许用户与其他东西共享锁。

这个 class 的编写方式是让它从自身外部使用锁,或者将自己用作锁。为什么不明显,因为没有给出上下文,我假设有一种情况,在这个地图和其他东西上需要粗粒度的锁定。

我更喜欢

private final Object mutex;

public SynchronizedMap(Map<K,V> map, Object mutex) {
    m = map;
    this.mutex = mutex;
}

public SynchronizedMap(Map<K,V> map) {
    this(map, new Object());
}

因为这样至少可以选择在对象的控制下独占锁定。

this这里指的是SynchronizedMap对象。

顺便说一句,可能它不使用私有锁,因此它可以支持客户端锁定。

正如另一个答案中已经指出的那样:一般来说,根据经验,最好有一个明确的、专用的、私有的 "lock" 对象,而不是公开 synchronized 通过public方法(在后一种情况下,对象本身将是锁,这在某些情况下很容易导致死锁)

然而,这里的情况有点不同,因为所有这些都指的是Collectionsclass的私有内部class。特别是,有一个明确的 mutex 参数的主要原因是这个互斥锁可以在多个实例之间 共享 。构造函数

SynchronizedMap(Map<K,V> m, Object mutex)

(仅!)在子 class 中调用,即在

中调用
SynchronizedSortedMap(SortedMap<K,V> m, Object mutex) {
    super(m, mutex);
    sm = m;
}

它只是将给定的互斥锁传递给 SynchronizedMap。此构造函数又在 SynchronizedSortedSet class 的 subMaptailMapheadMap 方法中调用。例如:

public SortedMap<K,V> subMap(K fromKey, K toKey) {
    synchronized (mutex) {
        return new SynchronizedSortedMap<>(
            sm.subMap(fromKey, toKey), mutex);
    }
}

这里,实际映射的互斥量也传递给子映射。

所以这里的效果是same mutex 用于映射及其子映射。如果 SynchronizedMap 中的同步与 synchronized(m).

中的委托映射同步,这将根本不可能。