All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.cedarsoftware.util.ConcurrentList Maven / Gradle / Ivy

The newest version!
package com.cedarsoftware.util;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.RandomAccess;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Supplier;

/**
 * A thread-safe implementation of the {@link List} interface, designed for use in highly concurrent environments.
 * 

* The {@code ConcurrentList} can be used either as a standalone thread-safe list or as a wrapper to make an existing * list thread-safe. It ensures thread safety without duplicating elements, making it suitable for applications * requiring synchronized access to list data. *

* *

Features

*
    *
  • Standalone Mode: Use the no-argument constructor to create a new thread-safe {@code ConcurrentList}.
  • *
  • Wrapper Mode: Pass an existing {@link List} to the constructor to wrap it with thread-safe behavior.
  • *
  • Read-Only Iterators: The {@link #iterator()} and {@link #listIterator()} methods return a read-only * snapshot of the list at the time of the call, ensuring safe iteration in concurrent environments.
  • *
  • Unsupported Operations: Due to the dynamic nature of concurrent edits, the * {@link #subList(int, int)} method is not implemented.
  • *
* *

Thread Safety

*

* All public methods of {@code ConcurrentList} are thread-safe, ensuring that modifications and access * operations can safely occur concurrently. However, thread safety depends on the correctness of the provided * backing list in wrapper mode. *

* *

Usage

*
{@code
 * // Standalone thread-safe list
 * ConcurrentList standaloneList = new ConcurrentList<>();
 * standaloneList.add("Hello");
 * standaloneList.add("World");
 *
 * // Wrapping an existing list
 * List existingList = new ArrayList<>();
 * existingList.add("Java");
 * existingList.add("Concurrency");
 * ConcurrentList wrappedList = new ConcurrentList<>(existingList);
 * }
* *

Performance Considerations

*

* The {@link #iterator()} and {@link #listIterator()} methods return read-only views created by copying * the list contents, which ensures thread safety but may incur a performance cost for very large lists. * Modifications to the list during iteration will not be reflected in the iterators. *

* *

Additional Notes

*
    *
  • {@code ConcurrentList} supports {@code null} elements if the underlying list does.
  • *
  • {@link #subList(int, int)} throws {@link UnsupportedOperationException}.
  • *
  • Implements {@link Serializable} and {@link RandomAccess} with a fair {@link ReentrantReadWriteLock}.
  • *
* * @param The type of elements in this list * * @author John DeRegnaucourt ([email protected]) *
* Copyright (c) Cedar Software LLC *

* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at *

* License *

* Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * @see List */ public final class ConcurrentList implements List, RandomAccess, Serializable { private static final long serialVersionUID = 1L; private final List list; private final transient ReadWriteLock lock = new ReentrantReadWriteLock(true); /** * No-arg constructor to create an empty ConcurrentList, wrapping an ArrayList. */ public ConcurrentList() { this.list = new ArrayList<>(); } /** * Initial capacity support */ public ConcurrentList(int size) { this.list = new ArrayList<>(size); } /** * Use this constructor to wrap a List (any kind of List) and make it a ConcurrentList. * No duplicate of the List is created and the original list is operated on directly. * @param list List instance to protect. */ public ConcurrentList(List list) { if (list == null) { throw new IllegalArgumentException("List cannot be null"); } this.list = list; } // Immutable APIs @Override public boolean equals(Object other) { return withReadLock(() -> list.equals(other)); } @Override public int hashCode() { return withReadLock(list::hashCode); } @Override public String toString() { return withReadLock(list::toString); } @Override public int size() { return withReadLock(list::size); } @Override public boolean isEmpty() { return withReadLock(list::isEmpty); } @Override public boolean contains(Object o) { return withReadLock(() -> list.contains(o)); } @Override public boolean containsAll(Collection c) { return withReadLock(() -> list.containsAll(c)); } @Override public E get(int index) { return withReadLock(() -> list.get(index)); } @Override public int indexOf(Object o) { return withReadLock(() -> list.indexOf(o)); } @Override public int lastIndexOf(Object o) { return withReadLock(() -> list.lastIndexOf(o)); } @Override public Iterator iterator() { return withReadLock(() -> new ArrayList<>(list).iterator()); } @Override public Object[] toArray() { return withReadLock(list::toArray); } @Override public T[] toArray(T[] a) { return withReadLock(() -> list.toArray(a)); } // Mutable APIs @Override public boolean add(E e) { return withWriteLock(() -> list.add(e)); } @Override public boolean addAll(Collection c) { return withWriteLock(() -> list.addAll(c)); } @Override public boolean addAll(int index, Collection c) { return withWriteLock(() -> list.addAll(index, c)); } @Override public void add(int index, E element) { withWriteLockVoid(() -> list.add(index, element)); } @Override public E set(int index, E element) { return withWriteLock(() -> list.set(index, element)); } @Override public E remove(int index) { return withWriteLock(() -> list.remove(index)); } @Override public boolean remove(Object o) { return withWriteLock(() -> list.remove(o)); } @Override public boolean removeAll(Collection c) { return withWriteLock(() -> list.removeAll(c)); } @Override public boolean retainAll(Collection c) { return withWriteLock(() -> list.retainAll(c)); } @Override public void clear() { withWriteLockVoid(() -> list.clear()); } @Override public ListIterator listIterator() { return withReadLock(() -> new ArrayList<>(list).listIterator()); } @Override public ListIterator listIterator(int index) { return withReadLock(() -> new ArrayList<>(list).listIterator(index)); } @Override public List subList(int fromIndex, int toIndex) { throw new UnsupportedOperationException("subList not implemented for ConcurrentList"); } private T withReadLock(Supplier operation) { lock.readLock().lock(); try { return operation.get(); } finally { lock.readLock().unlock(); } } private void withReadLockVoid(Runnable operation) { lock.readLock().lock(); try { operation.run(); } catch (RuntimeException e) { // swallow to ensure the lock is properly released } finally { lock.readLock().unlock(); } } private T withWriteLock(Supplier operation) { lock.writeLock().lock(); try { return operation.get(); } finally { lock.writeLock().unlock(); } } private void withWriteLockVoid(Runnable operation) { lock.writeLock().lock(); try { operation.run(); } finally { lock.writeLock().unlock(); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy