com.yahoo.yolean.concurrent.ThreadRobustList Maven / Gradle / Ivy
Show all versions of vespajlib Show documentation
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.yolean.concurrent;
import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* This class implements a thread-safe, lock-free list of Objects that supports multiple readers and a single writer.
* Because there are no locks or other memory barriers involved, there exists no happens-before relationship
* among calls to either methods of the ThreadRobustList
. This means that there are no guarantees as to when
* (or even if) an item {@link #add(Object)}ed becomes visible through {@link #iterator()}. If visibility is required,
* either use explicit synchronization between reader and writer thread, or move to a different concurrent collection
* (e.g. CopyOnWriteArrayList
).
* Because it is lock-free, the ThreadRobustList
has minimal overhead to both reading and writing. The
* iterator offered by this class always observes the list in a consistent state, and it never throws a
* ConcurrentModificationException
.
* The ThreadRobustList
does not permit adding null
items.
* The usage of ThreadRobustList
has no memory consistency effects.
*
* @author Steinar Knutsen
* @author bratseth
* @since 5.1.15
*/
public class ThreadRobustList implements Iterable {
private Object[] items;
private int next = 0;
/**
* Constructs a new instance of this class with an initial capacity of 10
.
*/
public ThreadRobustList() {
this(10);
}
/**
* Constructs a new instance of this class with a given initial capacity.
*
* @param initialCapacity the initial capacity of this list
*/
public ThreadRobustList(int initialCapacity) {
items = new Object[initialCapacity];
}
/**
* Returns whether or not this list is empty.
*
* @return true
if this list has zero items
*/
public boolean isEmpty() {
return next == 0;
}
/**
* Adds an item to this list. As opposed to CopyOnWriteArrayList
, items added to this list may become
* visible to iterators created before a call to this method.
*
* @param item the item to add
* @throws NullPointerException if item
is null
*/
public void add(T item) {
if (item == null) {
throw new NullPointerException();
}
Object[] workItems = items;
if (next >= items.length) {
workItems = Arrays.copyOf(workItems, 20 + items.length * 2);
workItems[next++] = item;
items = workItems;
} else {
workItems[next++] = item;
}
}
/**
* Returns an iterator over the items in this list. As opposed to CopyOnWriteArrayList
, this iterator
* may see items added to the ThreadRobustList
even if they occur after a call to this method.
* The returned iterator does not support remove()
.
*
* @return an iterator over this list
*/
@Override
public Iterator iterator() {
return new ThreadRobustIterator<>(items);
}
private static class ThreadRobustIterator implements Iterator {
final Object[] items;
int nextIndex = 0;
ThreadRobustIterator(Object[] items) {
this.items = items;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
@SuppressWarnings("unchecked")
@Override
public T next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
return (T)items[nextIndex++];
}
@Override
public boolean hasNext() {
if (nextIndex >= items.length) {
return false;
}
if (items[nextIndex] == null) {
return false;
}
return true;
}
}
}