CopyOnWriteArraySet in Java with Real-World Example

CopyOnWriteArraySet is a thread-safe implementation of the Set interface, backed by a CopyOnWriteArrayList. Like CopyOnWriteArrayList, all mutative operations (add, remove, etc.) are implemented by making a fresh copy of the underlying array. It is part of the java.util.concurrent package.

Key Points: 

Thread-Safety: All mutative operations are implemented by copying the underlying array, ensuring that the structure is safe from concurrent modifications. 

Uniqueness: Since it implements the Set interface, it does not allow duplicate elements. 

Iteration Behavior: Iterators for this set never throw ConcurrentModificationException

Performance: While the data can be iterated safely across multiple threads, the copy-on-write nature can be expensive for frequent modifications. It's most suitable for cases where iterations vastly outnumber modifications. 

Null Values: CopyOnWriteArraySet does not support null values.

Common Methods of CopyOnWriteArraySet

import java.util.Set;
import java.util.Iterator;
import java.util.concurrent.CopyOnWriteArraySet;

public class CopyOnWriteArraySetDemo {
    public static void main(String[] args) {
        // 1. Initialization
        Set<String> cowSet = new CopyOnWriteArraySet<>();
        System.out.println("Initialized set: " + cowSet);

        // 2. Adding elements
        cowSet.add("Apple");
        cowSet.add("Banana");
        cowSet.add("Cherry");
        System.out.println("After adding elements: " + cowSet);

        // 3. Check for a specific element
        System.out.println("Contains 'Apple'? " + cowSet.contains("Apple"));

        // 4. Remove an element
        cowSet.remove("Banana");
        System.out.println("After removing 'Banana': " + cowSet);

        // 5. Iterate over the set
        Iterator<String> iterator = cowSet.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }

        // 6. Add element during iteration
        for (String item : cowSet) {
            if ("Apple".equals(item)) {
                cowSet.add("Dragonfruit");
            }
            System.out.println(item);
        }

        System.out.println("After adding 'Dragonfruit' during iteration: " + cowSet);
    }
}

Output:

Initialized set: []
After adding elements: [Apple, Banana, Cherry]
Contains 'Apple'? true
After removing 'Banana': [Apple, Cherry]
Apple
Cherry
Apple
Cherry
After adding 'Dragonfruit' during iteration: [Dragonfruit, Apple, Cherry]

Explanation:

1. An empty CopyOnWriteArraySet of type String is initialized.

2. Elements are added to the set using the add method.

3. The contains method checks if a particular element exists in the set.

4. The remove method is used to delete the string "Banana" from the set.

5. The Iterator is used to traverse and print each element of the set.

6. The special feature of CopyOnWriteArraySet is demonstrated: it allows modifications like add during iteration without ConcurrentModificationException.

7. As we iterate through the set, we add "Dragonfruit" when we encounter "Apple".

Real-World Use Case: Online Classroom Students Registration using CopyOnWriteArraySet

import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

class Student {
    private String name;
    private int studentId;

    public Student(String name, int studentId) {
        this.name = name;
        this.studentId = studentId;
    }

    @Override
    public String toString() {
        return "ID: " + studentId + ", Name: " + name;
    }
}

public class OnlineClassroom {
    public static void main(String[] args) {
        // 1. Initialization
        Set<Student> registeredStudents = new CopyOnWriteArraySet<>();
        System.out.println("Initial registered students: " + registeredStudents);

        // 2. Registering students
        registeredStudents.add(new Student("Amit Sharma", 101));
        registeredStudents.add(new Student("Priya Malhotra", 102));
        registeredStudents.add(new Student("Rahul Joshi", 103));
        System.out.println("After registration: " + registeredStudents);

        // 3. Iterating and registering a student during iteration
        for (Student student : registeredStudents) {
            System.out.println(student);
            if (student.toString().contains("Priya Malhotra")) {
                registeredStudents.add(new Student("Deepika Gupta", 104));
            }
        }

        System.out.println("After registering a student during iteration: " + registeredStudents);
    }
}

Output:

Initial registered students: []
After registration: [ID: 101, Name: Amit Sharma, ID: 102, Name: Priya Malhotra, ID: 103, Name: Rahul Joshi]
ID: 101, Name: Amit Sharma
ID: 102, Name: Priya Malhotra
ID: 103, Name: Rahul Joshi
After registering a student during iteration: [ID: 104, Name: Deepika Gupta, ID: 101, Name: Amit Sharma, ID: 102, Name: Priya Malhotra, ID: 103, Name: Rahul Joshi]

Explanation:

1. An empty CopyOnWriteArraySet of type Student is initialized to keep track of registered students.

2. Students are added to the set using the add method. This ensures that duplicate students (in terms of memory address) won't get registered again.

3. As we iterate through the registered students, we add a new student named "Deepika Gupta" when we encounter "Priya Malhotra".

4. The special feature of CopyOnWriteArraySet is shown here: it allows adding elements during iteration without ConcurrentModificationException.

Comments