Class ConcurrentArrayList<T>
- java.lang.Object
-
- org.threadly.concurrent.collections.ConcurrentArrayList<T>
-
- Type Parameters:
T- type of object to retain
- All Implemented Interfaces:
java.lang.Iterable<T>,java.util.Collection<T>,java.util.Deque<T>,java.util.List<T>,java.util.Queue<T>,java.util.RandomAccess
public class ConcurrentArrayList<T> extends java.lang.Object implements java.util.List<T>, java.util.Deque<T>, java.util.RandomAccessA thread safe list implementation with an array back end. Make sure to read the javadocs carefully, as several functions behave subtly different from the java.util.List definition.The design of this implementation is NOT to completely avoid synchronization. We have a hybrid implementation of volatile and synchronized to allow for cheaper reading, but keeping high consistency. It works with the idea that the internal data is immutable. Each read has an immutable version of the data. Thus making writes more expensive (almost like a
CopyOnWriteArrayList).There are several differences between this and a CopyOnWriteArrayList. The first being that we don't have to copy the structure on every write operation. By setting the front and/or rear padding, we can add items to the front or end of the list while avoiding a copy operation. In addition removals also do not require a copy operation. Furthermore, this implementation differs from a CopyOnWriteArrayList is that it does allow some synchronization. Which can give higher consistency guarantees for some operations by allowing you to synchronize on the modification lock to perform multiple atomic operations.
The main motivation in implementing this was to avoid array copies as much as possible (which for large lists can be costly). But also the implementation to cheaply reposition an item in the list was necessary for other performance benefits.
A couple notable points is that subList calls are very cheap, but modifications to sublist are completely independent from their source list.
Unlike CopyOnWriteArrayList, Iterators can attempt to modify the state of the backing structure (assuming it still makes sense to do so). Although unlike CopyOnWriteArrayList iterators, once an Iterator is created it will never see updates to the structure. For that reason it is impossible to have a
ConcurrentModificationExcception.- Since:
- 1.0.0
-
-
Constructor Summary
Constructors Constructor Description ConcurrentArrayList()Constructs a newConcurrentArrayListwith a new internal NativeLock implementation.ConcurrentArrayList(int frontPadding, int rearPadding)Constructs a newConcurrentArrayListwith specific padding.
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description voidadd(int index, T element)booleanadd(T e)booleanaddAll(int index, java.util.Collection<? extends T> c)booleanaddAll(java.util.Collection<? extends T> c)voidaddFirst(T e)voidaddLast(T e)voidclear()booleancontains(java.lang.Object o)booleancontainsAll(java.util.Collection<?> c)java.util.Iterator<T>descendingIterator()Telement()booleanequals(java.lang.Object o)Tget(int index)TgetFirst()intgetFrontPadding()Getter for current amount to added padding to the front of new buffers.TgetLast()java.lang.ObjectgetModificationLock()If you want to chain multiple calls together and ensure that no threads modify the structure during that time you can get the lock to prevent additional modifications.intgetRearPadding()Getter for current amount to added padding to the rear of new buffers.inthashCode()intindexOf(java.lang.Object o)booleanisEmpty()java.util.Iterator<T>iterator()intlastIndexOf(java.lang.Object o)java.util.ListIterator<T>listIterator()java.util.ListIterator<T>listIterator(int index)booleanoffer(T e)booleanofferFirst(T e)booleanofferLast(T e)Tpeek()TpeekFirst()TpeekLast()Tpoll()TpollFirst()TpollLast()Tpop()voidpush(T e)Tremove()Tremove(int index)booleanremove(java.lang.Object o)booleanremoveAll(java.util.Collection<?> c)TremoveFirst()booleanremoveFirstOccurrence(java.lang.Object o)TremoveLast()booleanremoveLastOccurrence(java.lang.Object o)voidreposition(int originalIndex, int newIndex)Move a stored item located at an index to a new index.voidreposition(T item, int newIndex)Move a stored item to a new index.voidreposition(T item, int newIndex, boolean searchBackwards)Move a stored item to a new index.booleanretainAll(java.util.Collection<?> c)Tset(int index, T element)voidsetFrontPadding(int frontPadding)This changes the configuration for the front padding amount for future modification operations.voidsetRearPadding(int rearPadding)This changes the configuration for the rear padding amount for future modification operations.intsize()java.util.List<T>subList(int fromIndex, int toIndex)This returns a sub list from the current list.java.lang.Object[]toArray()<E> E[]toArray(E[] a)java.lang.StringtoString()voidtrimToSize()Trims the internally array to discard any unused storage.
-
-
-
Constructor Detail
-
ConcurrentArrayList
public ConcurrentArrayList()
Constructs a newConcurrentArrayListwith a new internal NativeLock implementation.
-
ConcurrentArrayList
public ConcurrentArrayList(int frontPadding, int rearPadding)Constructs a newConcurrentArrayListwith specific padding. Specifying the padding amounts can optimize this implementation more for the specific use case. If there is space in the array for adds to the front or end, then we are able to avoid an array copy.- Parameters:
frontPadding- padding to add to front of array to possible avoid array copiesrearPadding- padding to add to end of array to possible avoid array copies
-
-
Method Detail
-
getModificationLock
public java.lang.Object getModificationLock()
If you want to chain multiple calls together and ensure that no threads modify the structure during that time you can get the lock to prevent additional modifications.This lock should be synchronized on to prevent modifications.
- Returns:
- lock used internally
-
setFrontPadding
public void setFrontPadding(int frontPadding)
This changes the configuration for the front padding amount for future modification operations.- Parameters:
frontPadding- New value to over allocate the front of new buffers
-
setRearPadding
public void setRearPadding(int rearPadding)
This changes the configuration for the rear padding amount for future modification operations.- Parameters:
rearPadding- New value to over allocate the rear of new buffers
-
getFrontPadding
public int getFrontPadding()
Getter for current amount to added padding to the front of new buffers.- Returns:
- current amount to added padding to the front of new buffers
-
getRearPadding
public int getRearPadding()
Getter for current amount to added padding to the rear of new buffers.- Returns:
- current amount to added padding to the rear of new buffers
-
trimToSize
public void trimToSize()
Trims the internally array to discard any unused storage. It is good to invoke this if future adds are unlikely, and it is desired to keep memory usage minimal. This does not adjust the set front or rear padding, so additional modifications will expand the array based off those set values. To make sure additional modifications do not expand the array any more than necessary invokesetFrontPadding(int)andsetRearPadding(int)with0.
-
size
public int size()
-
isEmpty
public boolean isEmpty()
-
indexOf
public int indexOf(java.lang.Object o)
- Specified by:
indexOfin interfacejava.util.List<T>
-
lastIndexOf
public int lastIndexOf(java.lang.Object o)
- Specified by:
lastIndexOfin interfacejava.util.List<T>
-
contains
public boolean contains(java.lang.Object o)
-
containsAll
public boolean containsAll(java.util.Collection<?> c)
-
toArray
public java.lang.Object[] toArray()
-
toArray
public <E> E[] toArray(E[] a)
-
add
public boolean add(T e)
-
addAll
public boolean addAll(java.util.Collection<? extends T> c)
-
addAll
public boolean addAll(int index, java.util.Collection<? extends T> c)- Specified by:
addAllin interfacejava.util.List<T>
-
retainAll
public boolean retainAll(java.util.Collection<?> c)
-
clear
public void clear()
-
peek
public T peek()
-
removeAll
public boolean removeAll(java.util.Collection<?> c)
-
removeFirstOccurrence
public boolean removeFirstOccurrence(java.lang.Object o)
- Specified by:
removeFirstOccurrencein interfacejava.util.Deque<T>
-
removeLastOccurrence
public boolean removeLastOccurrence(java.lang.Object o)
- Specified by:
removeLastOccurrencein interfacejava.util.Deque<T>
-
remove
public boolean remove(java.lang.Object o)
-
offer
public boolean offer(T e)
-
remove
public T remove()
-
poll
public T poll()
-
element
public T element()
-
reposition
public void reposition(T item, int newIndex)
Move a stored item to a new index. By default a forward search will happen to find the item.- Parameters:
item- item to be movednewIndex- new index for placement
-
reposition
public void reposition(T item, int newIndex, boolean searchBackwards)
Move a stored item to a new index. If you have an idea if it is closer to the start or end of the list you can specify which end to start the search on.- Parameters:
item- item to be movednewIndex- new index for placementsearchBackwards- true to start from the end and search backwards
-
reposition
public void reposition(int originalIndex, int newIndex)Move a stored item located at an index to a new index. Provide the size for newIndex to move the item to the end of the list. Otherwise all items after the new index will be shifted right.- Parameters:
originalIndex- index for item to be moved to.newIndex- new index location for item.
-
iterator
public java.util.Iterator<T> iterator()
-
listIterator
public java.util.ListIterator<T> listIterator()
- Specified by:
listIteratorin interfacejava.util.List<T>
-
listIterator
public java.util.ListIterator<T> listIterator(int index)
- Specified by:
listIteratorin interfacejava.util.List<T>
-
descendingIterator
public java.util.Iterator<T> descendingIterator()
- Specified by:
descendingIteratorin interfacejava.util.Deque<T>
-
subList
public java.util.List<T> subList(int fromIndex, int toIndex)
This returns a sub list from the current list. The initial call is very cheap because it uses the current data backing to produce (no copying necessary).This differers from other subList implementations in that any modifications to this list will be treated as a completely new list, and wont ever reflect on the source list. This is very different from other java.util.List implementations, and should be noted carefully.
- Specified by:
subListin interfacejava.util.List<T>- Parameters:
fromIndex- start index (inclusive) for new list to includetoIndex- end index (exclusive) to be included in new list- Returns:
- new independent list
-
toString
public java.lang.String toString()
- Overrides:
toStringin classjava.lang.Object
-
equals
public boolean equals(java.lang.Object o)
-
-