The synchronizedNavigableSet()
method in Java is a utility method provided by the java.util.Collections
class. It returns a synchronized (thread-safe) navigable set backed by the specified navigable set. This method is particularly useful when you need to ensure that a navigable set is thread-safe in a concurrent environment.
Table of Contents
- Introduction
synchronizedNavigableSet()
Method Syntax- Examples
- Basic Usage of
synchronizedNavigableSet()
- Using
synchronizedNavigableSet()
with Custom Classes
- Basic Usage of
- Real-World Use Case
- Conclusion
Introduction
The Collections.synchronizedNavigableSet()
method provides a way to wrap a given navigable set with synchronized access, ensuring that only one thread can access the set at a time. This is crucial in concurrent applications where multiple threads might try to modify the set simultaneously, leading to race conditions or inconsistent data.
The returned navigable set is a synchronized view of the specified set, meaning that all operations on the set are synchronized using the set’s intrinsic lock. This includes operations such as adding, removing, or iterating over the elements, as well as any navigable-specific operations like lower
, floor
, ceiling
, and higher
.
synchronizedNavigableSet() Method Syntax
The syntax for the synchronizedNavigableSet()
method is as follows:
public static <T> NavigableSet<T> synchronizedNavigableSet(NavigableSet<T> s)
Parameters:
s
: The navigable set to be wrapped in a synchronized view.
Returns:
- A synchronized (thread-safe) navigable set backed by the specified navigable set.
Throws:
NullPointerException
if the specified navigable set is null.
Examples
Basic Usage of synchronizedNavigableSet()
The following example demonstrates how to use the synchronizedNavigableSet()
method to create a synchronized view of a navigable set.
Example
import java.util.Collections;
import java.util.Iterator;
import java.util.NavigableSet;
import java.util.TreeSet;
public class SynchronizedNavigableSetExample {
public static void main(String[] args) {
// Create a regular TreeSet
NavigableSet<String> set = new TreeSet<>();
set.add("Apple");
set.add("Banana");
set.add("Cherry");
// Create a synchronized (thread-safe) navigable set backed by the TreeSet
NavigableSet<String> synchronizedSet = Collections.synchronizedNavigableSet(set);
// Display the synchronized navigable set
System.out.println("Synchronized Navigable Set: " + synchronizedSet);
// Use synchronized block for iteration to ensure thread safety
synchronized (synchronizedSet) {
Iterator<String> iterator = synchronizedSet.iterator();
while (iterator.hasNext()) {
System.out.println("Element: " + iterator.next());
}
}
// Perform navigable operations
synchronized (synchronizedSet) {
System.out.println("Lower than Banana: " + synchronizedSet.lower("Banana"));
System.out.println("Floor of Banana: " + synchronizedSet.floor("Banana"));
System.out.println("Ceiling of Banana: " + synchronizedSet.ceiling("Banana"));
System.out.println("Higher than Banana: " + synchronizedSet.higher("Banana"));
}
// Adding and removing elements in a synchronized navigable set
synchronized (synchronizedSet) {
synchronizedSet.add("Date");
synchronizedSet.remove("Apple");
}
// Display the modified synchronized navigable set
System.out.println("Modified Synchronized Navigable Set: " + synchronizedSet);
}
}
Output:
Synchronized Navigable Set: [Apple, Banana, Cherry]
Element: Apple
Element: Banana
Element: Cherry
Lower than Banana: Apple
Floor of Banana: Banana
Ceiling of Banana: Banana
Higher than Banana: Cherry
Modified Synchronized Navigable Set: [Banana, Cherry, Date]
Using synchronizedNavigableSet() with Custom Classes
You can also use the synchronizedNavigableSet()
method with sets containing instances of custom classes.
Example
import java.util.Collections;
import java.util.Iterator;
import java.util.NavigableSet;
import java.util.TreeSet;
class Student implements Comparable<Student> {
String name;
int age;
Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public int compareTo(Student other) {
return Integer.compare(this.age, other.age);
}
@Override
public String toString() {
return name + " (" + age + ")";
}
}
public class CustomSynchronizedNavigableSetExample {
public static void main(String[] args) {
// Create a navigable set of students
NavigableSet<Student> students = new TreeSet<>();
students.add(new Student("Amit", 20));
students.add(new Student("Neha", 22));
students.add(new Student("Raj", 19));
// Create a synchronized (thread-safe) navigable set backed by the student set
NavigableSet<Student> synchronizedStudents = Collections.synchronizedNavigableSet(students);
// Display the synchronized student navigable set
System.out.println("Synchronized Student Navigable Set: " + synchronizedStudents);
// Use synchronized block for iteration to ensure thread safety
synchronized (synchronizedStudents) {
Iterator<Student> iterator = synchronizedStudents.iterator();
while (iterator.hasNext()) {
System.out.println("Student: " + iterator.next());
}
}
// Perform navigable operations
synchronized (synchronizedStudents) {
System.out.println("Lower than Neha: " + synchronizedStudents.lower(new Student("", 22)));
System.out.println("Floor of Neha: " + synchronizedStudents.floor(new Student("", 22)));
System.out.println("Ceiling of Neha: " + synchronizedStudents.ceiling(new Student("", 22)));
System.out.println("Higher than Neha: " + synchronizedStudents.higher(new Student("", 22)));
}
// Modifying the synchronized navigable set
synchronized (synchronizedStudents) {
synchronizedStudents.add(new Student("Vikram", 21));
synchronizedStudents.remove(new Student("Amit", 20));
}
// Display the modified synchronized student navigable set
System.out.println("Modified Synchronized Student Navigable Set: " + synchronizedStudents);
}
}
Output:
Synchronized Student Navigable Set: [Raj (19), Amit (20), Neha (22)]
Student: Raj (19)
Student: Amit (20)
Student: Neha (22)
Lower than Neha: Amit (20)
Floor of Neha: Neha (22)
Ceiling of Neha: Neha (22)
Higher than Neha: null
Modified Synchronized Student Navigable Set: [Raj (19), Vikram (21), Neha (22)]
Explanation:
- Synchronized View: The
synchronizedNavigableSet()
method returns a synchronized view of the specified navigable set, ensuring thread-safe access. - Synchronized Block: When iterating over the synchronized navigable set, a synchronized block is used to avoid concurrent modification exceptions and ensure thread safety.
- Custom Class: The method works with custom class instances, allowing you to create synchronized navigable sets with user-defined objects.
- Navigable Operations: The example demonstrates the use of navigable operations such as
lower
,floor
,ceiling
, andhigher
within the synchronized block.
Real-World Use Case
Thread-Safe Access to a Shared Sorted Resource
In real-world applications, the synchronizedNavigableSet()
method can be used to manage thread-safe access to shared resources, such as a set of sorted data in a multi-threaded environment.
Example
Imagine a scenario where you need to manage a shared set of sorted tasks in a concurrent application.
import java.util.Collections;
import java.util.Iterator;
import java.util.NavigableSet;
import java.util.TreeSet;
class Task implements Comparable<Task> {
String description;
int priority;
Task(String description, int priority) {
this.description = description;
this.priority = priority;
}
@Override
public int compareTo(Task other) {
return Integer.compare(this.priority, other.priority);
}
@Override
public String toString() {
return description + " (Priority: " + priority + ")";
}
}
public class TaskManager {
private final NavigableSet<Task> tasks;
public TaskManager() {
// Initialize the task set and wrap it in a synchronized view
this.tasks = Collections.synchronizedNavigableSet(new TreeSet<>());
}
public void addTask(Task task) {
synchronized (tasks) {
tasks.add(task);
}
}
public void removeTask(Task task) {
synchronized (tasks) {
tasks.remove(task);
}
}
public void displayTasks() {
// Use synchronized block for iteration to ensure thread safety
synchronized (tasks) {
Iterator<Task> iterator = tasks.iterator();
while (iterator.hasNext()) {
System.out.println("Task: " + iterator.next());
}
}
}
public Task getHighestPriorityTask() {
synchronized (tasks) {
return tasks.pollFirst();
}
}
public static void main(String[] args) {
TaskManager taskManager = new TaskManager();
// Add tasks to the manager
taskManager.addTask(new Task("Review code", 2));
taskManager.addTask(new Task("Write tests", 1));
taskManager.addTask(new Task("Deploy application", 3));
// Display all tasks
System.out.println("Task List:");
taskManager.displayTasks();
// Get and remove the highest priority task
Task highestPriorityTask = taskManager.getHighestPriorityTask();
System.out.println("\nHighest Priority Task: " + highestPriorityTask);
// Display remaining tasks
System.out.println("\nRemaining Task List:");
taskManager.displayTasks();
}
}
Output:
Compilation failed.
Explanation:
- Task Manager: The
TaskManager
class manages a navigable set of tasks, ensuring thread-safe access by wrapping the set in a synchronized view. - Concurrent Environment: The
synchronizedNavigableSet()
method is used to synchronize access to the shared set, preventing race conditions and ensuring data consistency. - Priority Management: The example demonstrates the use of navigable operations to manage task priorities and retrieve the highest-priority task.
Conclusion
The Collections.synchronizedNavigableSet()
method is a powerful utility for creating synchronized (thread-safe) navigable sets in Java. By providing a simple way to wrap navigable sets with synchronized access, it enhances the flexibility and safety of your code in concurrent environments. This method is particularly valuable in scenarios where you need to manage shared resources or ensure thread-safe access to sorted data, improving the robustness and maintainability of your Java applications.