从collections类中获取一个同步collection会同步一个类吗?

时间:2019-05-28 02:35:04

标签: java multithreading collections synchronized

我试图了解synchronizedCollectionsynchronizedListsynchronizedMapsynchronizedSet和其他此类方法的作用。据我了解,同步可以在块和方法上完成,而不能在类上完成,所以让我们说一下我是否有一个哈希映射。

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

问题

  1. 所以上述代码只是同步了整个syncHashMap类,还是 里面的每个方法?

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

在此先感谢您的指导。

5 个答案:

答案 0 :(得分:1)

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

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

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

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

答案 1 :(得分:0)

  

那么上面的代码只是同步了整个syncHashMap类或其中的每个方法吗?

Collections.syncrhonized*返回的集合实际上是自定义实现,其方法在互斥体上同步。例如,这是Collections.synchronizedMap的实现:

public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) {
    return new SynchronizedMap<>(m);
}

看看SynchronizedMap的某些方法,我们看到:

public int size() {
    synchronized (mutex) {return m.size();}
}

public boolean isEmpty() {
    synchronized (mutex) {return m.isEmpty();}
}

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

如果我们可以在多线程场景中简单地使用诸如ConcurrentHashMap或SynchronizedMap之类的线程安全集合,那么Collections类中的Collections.synchronizedMap(hashMap)和其他类似方法有什么需求

Collections#synchronized*对于要确保在给定时间在任何线程上仅执行集合的一种方法很有用。这也称为更新一致性

请参阅:ConcurrentHashMap vs Synchronized HashMap

答案 2 :(得分:0)

据我所知Collections.synchronizedMap不保证存储对象内的字段值将被同步,但是在{{1 }} 方法。它不保证其他任何内容。每当在另一个线程中修改同步映射时,其他线程中相同映射的其他引用将同步。

根据source和Java文档,这是我对此的肤浅理解。

答案 3 :(得分:0)

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

同步

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

synchronized块也是一种同步方式,尽管正确地使用它{em> 需要更多经验。

Mutex

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

线程安全

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

答案

具有前几段的知识,可以回答您的问题:不,它不会同步类。它根本不会改变原始的new实现。 但是,它确实为该类创建了一个读写线程安全的同步可变代理。

答案 4 :(得分:0)

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

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

要回答您的问题:

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

是的。只需查看Collections.SynchronizedMap here的源代码即可。注意,几乎每种方法都有 synchronized(mutex)块。

  1. 如果我们可以在多线程方案中简单地使用诸如ConcurrentHashMap或SynchronizedMap之类的线程安全集合,那么Collections类中的Collections.synchronizedMap(hashMap)和其他类似方法有什么需求?

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

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