互斥对象问题

时间:2015-03-11 04:05:37

标签: java multithreading mutex

我正在查看Collections.synhronizedMap()的java代码。我发现它已经低于实现。现在我的问题是 1)为什么我们使用synchronized(互斥) 2)如果我们使用synchronized(m)

该怎么办?

我理解的是,如果我们进行同步(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;

2 个答案:

答案 0 :(得分:4)

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

将互斥锁与地图分开是更好的方式。如果传入的映射使其他线程同步,那么这不会影响该对象。将锁与地图分开可让用户单独指定锁,因此它允许用户与其他人共享锁。

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

我更喜欢像

这样的东西
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对象。

BTW,可能它不使用私有锁,因此它可以支持客户端锁定。

答案 1 :(得分:2)

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

但是,这里的情况有点不同,因为所有这些都引用了Collections类的私有内部类。特别是,存在明确mutex参数的主要原因是此互斥锁可以在多个实例之间共享。构造函数

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

是(仅!)在子类中调用,即在

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

只是将给定的互斥量传递给SynchronizedMap。反过来,此构造函数在subMap类的tailMapheadMapSynchronizedSortedSet方法中调用。例如:

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

此处,实际地图的互斥锁也会传递给子地图。

因此,这里的效果是相同的互斥锁用于地图及其子地图。如果SynchronizedMap中的同步正在委托地图上与synchronized(m)进行同步,那么这将无法实现。