admin管理员组文章数量:1441132
同步 Java 集合简介
1. 概述
集合框架是Java的关键组件。它提供了大量的接口和实现,使我们能够以简单的方式创建和操作不同类型的集合。
尽管使用普通的不同步集合总体上很简单,但在多线程环境(也称为并发编程)中工作时,它也可能成为一个令人生畏且容易出错的过程。
因此,Java 平台通过在Collections(.base/java/util/Collections.html#synchronizedCollection(java.util.Collection%29)类中实现的不同同步包装器为此方案提供了强大的支持。
通过这些包装器,可以通过多个静态工厂方法轻松创建所提供集合的同步视图。
在本教程中,我们将深入探讨这些静态同步包装器。此外,我们还将重点介绍同步集合和并发集合之间的区别。
2.syncdCollection方法
我们将在本综述中介绍的第一个同步包装器是syncdCollection() 方法。顾名思义,它返回由指定集合备份的线程安全集合。
现在,为了更清楚地了解如何使用此方法,让我们创建一个基本的单元测试:
代码语言:javascript代码运行次数:0运行复制Collection<Integer> syncCollection = Collections.synchronizedCollection(new ArrayList<>());
Runnable listOperations = () -> {
syncCollection.addAll(Arrays.asList(1, 2, 3, 4, 5, 6));
};
Thread thread1 = new Thread(listOperations);
Thread thread2 = new Thread(listOperations);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
assertThat(syncCollection.size()).isEqualTo(12);
}
Copy
如上所示,使用此方法创建所提供集合的同步视图非常简单。
为了演示该方法实际上返回线程安全集合,我们首先创建几个线程。
之后,我们以 lambda 表达式的形式将一个Runnable实例注入到它们的构造函数中。请记住,Runnable是一个函数式接口,因此我们可以将其替换为 lambda 表达式。
最后,我们只检查每个线程是否有效地将六个元素添加到同步集合中,因此其最终大小为 12。
3.syncdList方法
同样,与syncdCollection() 方法类似,我们可以使用syncdList()包装器创建一个同步列表。
正如我们所料,该方法返回指定列表的线程安全视图:
代码语言:javascript代码运行次数:0运行复制List<Integer> syncList = Collections.synchronizedList(new ArrayList<>());Copy
不出所料,syncdList() 方法的使用看起来与其更高级别对应的 synchronizedCollection() 几乎相同。
因此,正如我们在上一个单元测试中所做的那样,一旦我们创建了一个同步的 List,我们就可以生成多个线程。完成此操作后,我们将使用它们以线程安全的方式访问/操作目标列表。
此外,如果我们想迭代同步集合并防止意外结果,我们应该显式提供我们自己的线程安全循环实现。因此,我们可以使用同步块来实现这一点:
代码语言:javascript代码运行次数:0运行复制List<String> syncCollection = Collections.synchronizedList(Arrays.asList("a", "b", "c"));
List<String> uppercasedCollection = new ArrayList<>();
Runnable listOperations = () -> {
synchronized (syncCollection) {
syncCollection.forEach((e) -> {
uppercasedCollection.add(e.toUpperCase());
});
}
};
Copy
在我们需要迭代同步集合的所有情况下,我们应该实现这个习惯用法。这是因为同步集合上的迭代是通过对集合的多次调用来执行的。因此,它们需要作为单个原子操作执行。
同步块的使用确保了操作的原子性。
4.syncdMap方法
Collections类实现了另一个简洁的同步包装器,称为syncdMap()。我们可以使用它来轻松创建同步Map。
该方法返回提供的Map实现的线程安全:
代码语言:javascript代码运行次数:0运行复制Map<Integer, String> syncMap = Collections.synchronizedMap(new HashMap<>());
Copy
5.syncdSortedMap方法
还有一个syncdMap() 方法的对应实现。它被称为syncdSortedMap(),我们可以用它来创建一个同步的SortedMap实例:
代码语言:javascript代码运行次数:0运行复制Map<Integer, String> syncSortedMap = Collections.synchronizedSortedMap(new TreeMap<>());
Copy
6.syncdSet方法
接下来,在这篇文章中我们有syncdSet() 方法。顾名思义,它允许我们以最小的麻烦创建同步集。
包装器返回由指定Set 支持的线程安全集合:
代码语言:javascript代码运行次数:0运行复制Set<Integer> syncSet = Collections.synchronizedSet(new HashSet<>());
Copy
7.syncdSortedSet方法
最后,我们将在这里展示的最后一个同步包装器是syncdSortedSet()。
与到目前为止我们审查过的其他包装器实现类似,该方法返回给定SortedSet 的线程安全版本:
代码语言:javascript代码运行次数:0运行复制SortedSet<Integer> syncSortedSet = Collections.synchronizedSortedSet(new TreeSet<>());
Copy
8. ConcurrentHashMap和BlockingQueue
到目前为止,我们仔细研究了集合框架的同步包装器。
现在,让我们关注同步集合和并发集合之间的差异,例如ConcurrentHashMap和BlockingQueue实现。
8.1. 同步集合
同步集合通过内在锁定实现线程安全,并且整个集合都是锁定的。内在锁是通过封装集合的方法中的同步块实现的。
正如我们所期望的,同步集合可以确保多线程环境中的数据一致性/完整性。然而,它们可能会带来性能上的损失,因为一次只能有一个线程访问集合(也称为同步访问)。
有关如何使用同步方法和块的详细指南,请查看我们关于该主题的文章。
8.2. 并发集合
并发集合(例如ConcurrentHashMap)通过将其数据划分为段来实现线程安全。例如,在ConcurrentHashMap中,不同的线程可以在每个段上获取锁,因此多个线程可以同时访问Map(也称为并发访问)。
由于并发线程访问的固有优势,并发集合的性能比同步集合高得多。
因此,选择使用哪种类型的线程安全集合取决于每个用例的要求,应相应地对其进行评估。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。 原始发表:2023-02-22,如有侵权请联系 cloudcommunity@tencent 删除并发集合同步线程安全java本文标签: 同步 Java 集合简介
版权声明:本文标题:同步 Java 集合简介 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/biancheng/1747900833a2773678.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论