【问题标题】:Mutex vs object issue互斥体与对象问题
【发布时间】:2015-03-11 04:05:37
【问题描述】:

我正在查看 Collections.synhronizedMap() 的 java 代码。我发现它有以下实现。现在我的问题是 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;

【问题讨论】:

    标签: java multithreading mutex


    【解决方案1】:

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

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

    这个类的编写方式是让它使用来自自身外部的锁,或者将自己用作锁。为什么不明显,因为没有给出上下文,我假设存在这样一种情况,即在此映射中需要粗粒度锁定以及其他一些东西。

    我更喜欢类似的东西

    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 对象。

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

    【讨论】:

    • 您能否详细描述一下。我在其他类中也看到过这个 final ReentrantLock lock = this.lock;你也可以建议我阅读任何链接以完全理解这一点。请考虑我对此的外行。它将帮助我以及其他阅读本文或尝试了解当前并发场景的人。
    • 但是看构造函数! mutex = this。呸!这个实现在我看来完全落后。并不是说“私有” Map 包含对传递给构造函数的对象的引用。 @AnilSharma 我假设,因为整个类被声明为 static 它是一个 inner 类,并且可能有一些原因导致它以这种方式编写,但断章取义,它没有看起来像是优秀软件设计的光辉典范。
    • @Anil:我不知道你需要什么细节,你可以让你的问题更具体。
    • @jameslarge “私有”地图包含对构造函数参数的引用,因为这是地图的视图。这是预期的行为。
    • 对不起,来自 java 的人不需要那么多批评。它是 java.util.Collections 类的一段代码。基本上我正在查看 Collections.synchronizedMap() 方法的同步。实际上我不想粘贴超过 1000 行的整个类,所以只粘贴了那部分。
    【解决方案2】:

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

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

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

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

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

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

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

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

    所以这里的效果是 same 互斥体用于映射及其子映射。如果SynchronizedMap 中的同步在委托映射上与synchronized(m) 同步,这根本不可能。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-11-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-18
      • 2015-08-17
      • 1970-01-01
      相关资源
      最近更新 更多