【问题标题】:Does getting a synchronized collection from collections class synchronize a class?从集合类获取同步集合是否会同步一个类?
【发布时间】:2019-10-13 12:23:55
【问题描述】:

我试图了解synchronizedCollectionsynchronizedListsynchronizedMapsynchronizedSet 和其他此类方法的作用。据我了解,同步可以在块和方法上完成,而不是在类上,所以假设我有一个哈希图。

HashMap<Integer,String> hashMap = new HashMap<Integer,String>();
HashMap<Integer,String> syncHashMap = Collections.synchronizedMap(hashMap);

问题

  1. 上面的代码也同步了整个syncHashMap类或 里面的每一个方法?

  2. 如果我们可以简单地使用线程安全集合,例如 ConcurrentHashMapSynchronizedMap 在多线程场景中那么需要什么 Collections.synchronizedMap(hashMap) 和其他类似的方法在 集合类

非常感谢这方面的一些指导,在此先感谢。

【问题讨论】:

  • 我认为您对同步有点困惑。您不同步代码。代码在对象上同步。在这种情况下,所有标准 Map 方法都会在 synchronizedMap() 返回的对象上同步。
  • 您应该从了解对象、类和变量之间的区别开始。 syncHashMap 是一个变量,包含对对象的引用。

标签: java multithreading collections synchronized


【解决方案1】:
  1. 那么上面的代码是同步了整个syncHashMap类还是同步了其中的每个方法?

不确定同步整个syncHashMap 类其中的每个方法 是什么意思。

如果你查看方法Collections.synchronizedMap(hashMap)的源代码,你会发现它使用synchronized关键字来装饰原始地图的每个方法。这意味着对于修饰的地图对象,您一次只能调用其方法之一。但是不同的地图,你可以一次调用。

  1. 您可以在这里找到它们的用法。 ConcurrentHashMap vs Synchronized HashMap

【讨论】:

    【解决方案2】:

    据我了解,Collections.synchronizedMap 不保证存储对象内的字段值将同步,但地图内的每个 entry 将在 synchronized 方法中修改时同步。它不保证其他任何事情。每当在另一个线程中修改同步映射时,其他线程中相同映射的其他引用将同步。

    这是我根据这个source以及Java文档对它的粗浅理解。

    【讨论】:

    • 没有人询问嵌套字段。 IntegerString 无论如何都是不可变的。
    【解决方案3】:

    有几个术语涉及您所询问的主题。

    同步

    有许多接口和类可以帮助您在线程之间同步代码。 SemaphoreCyclicBarrier 或像 BlockingQueue 这样的同步集合。有关这些类的列表,请参阅 java.util.concurrent 包。

    synchronized 块也是一种同步方式,但正确使用需要更多经验。

    互斥体

    不同的语言(和库)以不同的方式实现标准互斥锁。这个想法保持不变 - 为了继续执行特定代码,一个互斥令牌,必须获取一个互斥锁。在 java 中,这种获取发生在进入 synchronized 块之前。

    线程安全

    简单地说,当一个类的所有方法都可以从任意数量的线程同时以任意顺序访问时,它就是线程安全的。有几种方法可以实现线程安全。例如,字符串是线程安全的。它们不是同步的,但它们是不可变的,这也会导致线程安全。所有Collections.synchronized*() 方法都返回集合的线程安全包装器,前提是所有未来*(*参见happens-before 关系)对它们的访问都是通过这些包装器执行的(这就是为什么初学者在@ 上调用Collections.synchronized*() 是一个很好的规则仅限 987654330@ 个对象。

    答案

    根据前面段落的知识,回答您的问题:不,它不会同步课程。它根本不会改变原来的Collection 实现。 但是,它确实为该类创建了一个读写线程安全的同步可变代理。

    【讨论】:

      【解决方案4】:

      在回答您的问题之前,让我们重申一些同步的基础知识

      • 同步始终在对象/实例上。每个同步实例都由一个锁(称为互斥锁)保护。
      • 任何在对象上调用同步方法的线程都必须先获取该锁,然后再调用该方法。
      • 为什么调用非同步方法不需要此锁获取。

      回答您的问题:

      1. 那么上面的代码是同步了整个syncHashMap类还是同步了其中的每个方法

      是的。看看 Collections.SynchronizedMap here 的源码就知道了。请注意,几乎每个方法都有 synchronized (mutex) 块。

      1. 如果我们可以在多线程场景中简单地使用 ConcurrentHashMap 或 SynchronizedMap 等线程安全集合,那么 Collections 类中需要 Collections.synchronizedMap(hashMap) 和其他类似方法吗?

      同步每个方法(包括只读类型的方法)都有缺点。它不必要地减慢了读取操作,因此您的观察是正确的,即使用诸如 ConcurrentHashMap 之类的实现,它只锁定正在修改集合的方法。只读方法不同步,因此在具有并发读/写操作的多线程场景中速度更快。

      Collections.synchronizedMap 提供的唯一优势是保留输入键的顺序。因此,当您需要时,您可以使用 Collections.synchronizedMap。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-11-18
        • 1970-01-01
        • 1970-01-01
        • 2013-03-04
        • 1970-01-01
        • 1970-01-01
        • 2011-06-02
        • 2020-03-23
        相关资源
        最近更新 更多