Java Collections.synchronizedSortedSet
上次修改时间:2025 年 4 月 20 日
Collections.synchronizedSortedSet 方法提供对已排序集合的线程安全访问。它返回一个由指定的已排序集合支持的同步(线程安全)已排序集合。此包装器确保安全的并发访问。
在多线程环境中,直接访问集合可能会导致问题。同步包装器通过同步所有操作来防止数据损坏。它是 Java Collections Framework 实用方法的一部分。
SortedSet 和同步基础知识
SortedSet 根据元素的自然顺序或比较器以升序维护元素。但是,诸如 TreeSet 之类的标准实现不是线程安全的。多线程访问需要同步。
Collections.synchronizedSortedSet 方法通过包装集合来解决此问题。对返回的集合的所有访问都与集合本身同步。这可以防止并发修改问题。
基本 SynchronizedSortedSet 示例
此示例演示如何从 TreeSet 创建同步的已排序集合。我们展示了诸如添加元素和迭代之类的基本操作。同步包装器确保线程安全。
package com.zetcode;
import java.util.Collections;
import java.util.SortedSet;
import java.util.TreeSet;
public class BasicSynchronizedSortedSet {
public static void main(String[] args) {
// Create a regular TreeSet
SortedSet<String> treeSet = new TreeSet<>();
// Wrap it in a synchronized sorted set
SortedSet<String> syncSet = Collections.synchronizedSortedSet(treeSet);
// Add elements
syncSet.add("Apple");
syncSet.add("Banana");
syncSet.add("Cherry");
// Iterate (must synchronize manually for iteration)
synchronized(syncSet) {
for (String fruit : syncSet) {
System.out.println(fruit);
}
}
System.out.println("Size: " + syncSet.size());
}
}
此代码围绕 TreeSet 创建一个同步包装器。现在对集合的所有操作都是线程安全的。请注意,迭代需要显式同步。输出显示按排序顺序排列的元素。
同步包装器确保安全的并发访问。但是,复合操作仍然需要外部同步。该示例演示了正确的迭代同步。
多线程访问示例
此示例显示了多个线程如何安全地访问同步的已排序集合。我们创建了两个并发添加元素的线程。同步包装器可以防止损坏。
package com.zetcode;
import java.util.Collections;
import java.util.SortedSet;
import java.util.TreeSet;
public class MultiThreadedSortedSet {
public static void main(String[] args) throws InterruptedException {
SortedSet<Integer> syncSet = Collections.synchronizedSortedSet(
new TreeSet<>());
// Create and start two threads
Thread t1 = new Thread(() -> addNumbers(syncSet, 0, 50));
Thread t2 = new Thread(() -> addNumbers(syncSet, 50, 100));
t1.start();
t2.start();
t1.join();
t2.join();
// Verify all numbers were added
System.out.println("Total elements: " + syncSet.size());
System.out.println("First: " + syncSet.first());
System.out.println("Last: " + syncSet.last());
}
private static void addNumbers(SortedSet<Integer> set, int start, int end) {
for (int i = start; i < end; i++) {
set.add(i);
}
}
}
此示例演示了线程安全的并发访问。两个线程同时将数字添加到集合中。同步包装器可以防止竞争条件。最终输出显示已正确添加所有数字。
请注意,虽然单个操作是线程安全的,但复合操作可能需要额外的同步。该示例显示了使用 join() 的正确线程协调。
Comparator 与 SynchronizedSortedSet
此示例演示了将自定义比较器与同步的已排序集合一起使用。我们创建一个不区分大小写的已排序集合,并将其包装以实现线程安全。比较器定义排序顺序。
package com.zetcode;
import java.util.Collections;
import java.util.Comparator;
import java.util.SortedSet;
import java.util.TreeSet;
public class ComparatorSortedSet {
public static void main(String[] args) {
// Create comparator for case-insensitive sorting
Comparator<String> ignoreCase = String.CASE_INSENSITIVE_ORDER;
// Create sorted set with comparator
SortedSet<String> treeSet = new TreeSet<>(ignoreCase);
// Wrap in synchronized set
SortedSet<String> syncSet = Collections.synchronizedSortedSet(treeSet);
// Add mixed-case elements
syncSet.add("apple");
syncSet.add("Banana");
syncSet.add("CHERRY");
syncSet.add("dATE");
// Iterate (with synchronization)
synchronized(syncSet) {
for (String fruit : syncSet) {
System.out.println(fruit);
}
}
}
}
此代码创建一个不区分大小写的已排序集合,并将其包装以实现线程安全。比较器确保正确的排序,而与大小写无关。同步包装器使所有操作都线程安全。
输出显示元素按大小写不敏感的方式排序。同步确保安全访问,即使多个线程同时修改集合。
SynchronizedSortedSet 的批量操作
此示例演示了对同步的已排序集合执行的批量操作。我们展示了 addAll、removeAll 和 retainAll 操作。每个操作都会自动同步。
package com.zetcode;
import java.util.Arrays;
import java.util.Collections;
import java.util.SortedSet;
import java.util.TreeSet;
public class BulkOperationsSortedSet {
public static void main(String[] args) {
SortedSet<String> syncSet = Collections.synchronizedSortedSet(
new TreeSet<>());
// Add multiple elements
syncSet.addAll(Arrays.asList("Apple", "Banana", "Cherry", "Date"));
System.out.println("After addAll: " + syncSet);
// Remove multiple elements
syncSet.removeAll(Arrays.asList("Banana", "Date"));
System.out.println("After removeAll: " + syncSet);
// Retain only specified elements
syncSet.retainAll(Arrays.asList("Apple", "Cherry", "Fig"));
System.out.println("After retainAll: " + syncSet);
// Check contains all
boolean hasAll = syncSet.containsAll(Arrays.asList("Apple", "Cherry"));
System.out.println("Contains all: " + hasAll);
}
}
此示例显示了对同步的已排序集合的批量操作。由于同步包装器,每个操作都是线程安全的。输出演示了每个操作如何修改集合。
使用元素组时,批量操作特别有用。同步包装器确保这些操作保持原子性和线程安全性。
迭代和子集操作
此示例演示了子集操作和正确的迭代技术。我们展示了 subSet、headSet 和 tailSet 方法。迭代需要显式同步。
package com.zetcode;
import java.util.Collections;
import java.util.SortedSet;
import java.util.TreeSet;
public class SubsetOperations {
public static void main(String[] args) {
SortedSet<Integer> syncSet = Collections.synchronizedSortedSet(
new TreeSet<>());
// Add numbers 1-100
for (int i = 1; i <= 100; i++) {
syncSet.add(i);
}
// Get subset 40-60
SortedSet<Integer> subSet = syncSet.subSet(40, 60);
System.out.println("Subset 40-60 size: " + subSet.size());
// Get headSet (elements < 25)
SortedSet<Integer> headSet = syncSet.headSet(25);
System.out.println("HeadSet <25 size: " + headSet.size());
// Get tailSet (elements >= 75)
SortedSet<Integer> tailSet = syncSet.tailSet(75);
System.out.println("TailSet >=75 size: " + tailSet.size());
// Iterate subset (with synchronization)
synchronized(syncSet) {
for (Integer num : subSet) {
System.out.print(num + " ");
}
}
}
}
此示例演示了对同步的已排序集合执行的子集操作。subSet、headSet 和 tailSet 方法创建原始集合的部分视图。这些视图也已同步。
输出显示不同子集的大小。同步迭代确保遍历期间的线程安全访问。子集操作对于处理排序数据的范围非常强大。
性能注意事项
此示例比较了同步和非同步的已排序集合之间的性能。我们测量两者的操作时间,以显示同步开销。该测试演示了何时需要同步。
package com.zetcode;
import java.util.Collections;
import java.util.SortedSet;
import java.util.TreeSet;
public class PerformanceComparison {
public static void main(String[] args) {
final int ELEMENTS = 100000;
// Unsynchronized set
SortedSet<Integer> treeSet = new TreeSet<>();
long start = System.currentTimeMillis();
for (int i = 0; i < ELEMENTS; i++) {
treeSet.add(i);
}
long unsyncTime = System.currentTimeMillis() - start;
// Synchronized set
SortedSet<Integer> syncSet = Collections.synchronizedSortedSet(
new TreeSet<>());
start = System.currentTimeMillis();
for (int i = 0; i < ELEMENTS; i++) {
syncSet.add(i);
}
long syncTime = System.currentTimeMillis() - start;
System.out.println("Unsynchronized add time: " + unsyncTime + "ms");
System.out.println("Synchronized add time: " + syncTime + "ms");
System.out.println("Overhead: " +
((double)(syncTime - unsyncTime)/unsyncTime * 100) + "%");
}
}
此代码比较了同步和非同步的已排序集合之间的性能。该测试将许多元素添加到两个集合中,并测量所花费的时间。输出显示了同步开销百分比。
同步会增加开销,但对于线程安全是必要的。在单线程场景中,首选非同步集合。该示例有助于理解性能权衡。
来源
Java Collections.synchronizedSortedSet 文档
在本文中,我们深入探讨了 Collections.synchronizedSortedSet。我们介绍了基本用法、多线程、比较器、批量操作、子集和性能。理解这些概念对于线程安全的已排序集合操作至关重要。
作者
列出所有Java教程。