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教程。