I need an ArrayList-like structure allowing just the following operations
get(int index)
add(E element)
set(int index, E element)
iterator()
Because of the iterator being used in many places, using Collections#synchronizedList would be too error-prone. The list can grow to a few thousand elements and gets used a lot, so I'm pretty sure, that CopyOnWriteArrayList will be too slow. I'll start with it to avoid premature optimizations, but I'd bet it won't work well.
Most accesses will be single-threaded reads. So I'm asking what's the proper data structure for this.
I though that wrapping the synchronizedList in something providing a synchronized iterator would do, but it won't because of the ConcurrentModificationException. Concenrning concurrent behavior, I obviously need that all changes will be visible by subsequent reads and iterators.
The iterator doesn't have to show a consistent snapshot, it may or may not see the updates via set(int index, E element) as this operation gets used only to replace an item with its updated version (containing some added information, which is irrelevant for the user of the iterator). The items are fully immutable.
I clearly stated why CopyOnWriteArrayList would not do. ConcurrentLinkedQueue is out of question as it lacks an indexed access. I need just a couple of operations rather than a fully fledged ArrayList. So unless any java concurrent list-related question is a duplicate of this question, this one is not.
In your case you can use a ReadWriteLock to access a backed List, this allows multiple Threads to read your list. Only if one Thread needs write access all reader-Thread must wait for the operation to complete. The JavaDoc make's it clear:
A ReadWriteLock maintains a pair of associated locks, one for
read-only operations and one for writing. The read lock may be held
simultaneously by multiple reader threads, so long as there are no
writers. The write lock is exclusive.
Here is a sample:
public class ConcurrentArrayList<T> {
/** use this to lock for write operations like add/remove */
private final Lock readLock;
/** use this to lock for read operations like get/iterator/contains.. */
private final Lock writeLock;
/** the underlying list*/
private final List<T> list = new ArrayList();
{
ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
readLock = rwLock.readLock();
writeLock = rwLock.writeLock();
}
public void add(T e){
writeLock.lock();
try{
list.add(e);
}finally{
writeLock.unlock();
}
}
public void get(int index){
readLock.lock();
try{
list.get(index);
}finally{
readLock.unlock();
}
}
public Iterator<T> iterator(){
readLock.lock();
try {
return new ArrayList<T>( list ).iterator();
//^ we iterate over an snapshot of our list
} finally{
readLock.unlock();
}
}
Related
i am currently using a ConcurrentLinkedQueue, so that I can use natural order FIFO and also use it in a thread safe application . I have a requirement to log the size of the queue every minute and given that this collection does not guarantee size and also cost to calculate size is O(N), is there any alternative bounded non blocking concurrent queue that I can use where in obtaining size will not be a costly operation and at the same time the add/remove operation is not expensive either?
If there is no collection, do I need to use LinkedList with locks?
If you really (REALLY) need to log a correct, current size of the Queue you are currently dealing with - you need to block. There is simply no other way. You can think that maintaining a separate LongAdder field might help, may be making your own interface as a wrapper around ConcurrentLinkedQueue, something like:
interface KnownSizeQueue<T> {
T poll();
long size();
}
And an implementation:
static class ConcurrentKnownSizeQueue<T> implements KnownSizeQueue<T> {
private final ConcurrentLinkedQueue<T> queue = new ConcurrentLinkedQueue<>();
private final LongAdder currentSize = new LongAdder();
#Override
public T poll() {
T result = queue.poll();
if(result != null){
currentSize.decrement();
}
return result;
}
#Override
public long size() {
return currentSize.sum();
}
}
I just encourage you to add one more method, like remove into the interface and try to reason about the code. You will, very shortly realize, that such implementations will still give you a wrong result. So, do not do it.
The only reliable way to get the size, if you really need it, is to block for each operation. This comes at a high price, because ConcurrentLinkedQueue is documented as:
This implementation employs an efficient non-blocking...
You will lose those properties, but if that is a hard requirement that does not care about that, you could write your own:
static class ParallelKnownSizeQueue<T> implements KnownSizeQueue<T> {
private final Queue<T> queue = new ArrayDeque<>();
private final ReentrantLock lock = new ReentrantLock();
#Override
public T poll() {
try {
lock.lock();
return queue.poll();
} finally {
lock.unlock();
}
}
#Override
public long size() {
try {
lock.lock();
ConcurrentLinkedQueue
return queue.size();
} finally {
lock.unlock();
}
}
}
Or, of course, you can use an already existing structure, like LinkedBlockingDeque or ArrayBlockingQueue, etc - depending on what you need.
I need to replace the first value in Deque with the new value, only
if the size will exceed the limit. I wrote this code to solve it:
final class Some {
final int buffer;
final Deque<Operation> operations = new ConcurrentLinkedDeque<>();
// constructors ommited;
#Override
public void register(final Operation operation) {
if (this.operations.size() == this.buffer) {
// remove the oldest operation
this.operations.removeFirst();
}
// add new operation to the tail
this.operations.addLast(operation);
}
#Override
public void apply() {
// take the fresh operation from tail and perform it
this.operations.removeLast().perform();
}
}
As you see, I have two methods, that modifies the Deque. I have doubts, that this code will work correctly in the multithreaded environment. The question is: is it safe to check the size() and then performing operations, that modifies the ConcurrentLinkedDeque afterward? I want to have as least locks as possible. So if this code won't work, then I had to introduce locking and then there is no point in the usage of ConcurrentLinkedDeque().
final class Some {
final int buffer;
final Deque<Operation> operations = new LinkedList<>();
final Lock lock = new ReentrantLock();
// constructors ommited;
#Override
public void register(final Operation operation) {
this.lock.lock();
try {
if (this.operations.size() == this.buffer) {
// remove the oldest operation
this.operations.removeFirst();
}
// add new operation to the tail
this.operations.addLast(operation);
} finally {
lock.unlock();
}
}
#Override
public void apply() {
this.lock.lock();
try {
// take the fresh operation from tail and perform it
this.operations.removeLast().perform();
} finally {
this.lock.unlock();
}
}
}
This is the alternative with the Lock. Is that the only way to achieve what I want? I am especially interested in trying to use the concurrent collections.
Concurrent collections are thread-safe when it comes to internal state. In other words, they
Allow multiple threads to read/write concurrently without having to worry that the internal state will become corrupted
Allow iteration and removal while other threads are modifying the collection
Not all, however. I believe CopyOnWriteArrayList's Iterator does not support the remove() operation
Guarantees things such as happens-before
Meaning a write by one thread will happen-before a read by a subsequent thread
However, they are not thread-safe across external method calls. When you call one method it will acquire whatever locks are necessary but those locks are released by the time the method returns. If you're not careful this can lead to a check-then-act race condition. Looking at your code
if (this.operations.size() == this.buffer) {
this.operations.removeFirst();
}
this.operations.addLast(operation);
the following can happen:
Thread-A checks size condition, result is false
Thread-A moves to add new Operation
Before Thread-A can add the Operation, Thread-B checks size condition which results in false as well
Thread-B goes to add new Operation
Thread-A does add new Operation
Oh, no! The Operation added by Thread-A causes the size threshold to be reached
Thread-B, already past the if statement, adds its Operation making the deque have one too many Operations
This is why a check-then-act requires external synchronization, which you do in your second example using a Lock. Note you could also use a synchronized block on the Deque.
Unrelated to your question: You call Operation.perform() in your second example while still holding the Lock. This means no other thread can attempt to add another Operation to the Deque while perform() executes. If this isn't desired you can change the code like so:
Operation op;
lock.lock();
try {
op = deque.pollLast(); // poll won't throw exception if there is no element
} finally {
lock.unlock();
}
if (op != null) {
op.perform();
}
From the doc of size()
BlockquoteBeware that, unlike in most collections, this method is NOT a constant-time operation. Because of the asynchronous nature of these deques, determining the current number of elements requires traversing them all to count them. Additionally, it is possible for the size to change during execution of this method, in which case the returned result will be inaccurate. Thus, this method is typically not very useful in concurrent applications.
While #Slaw is correct, also add that an addition/subtraction can occur during the traversal.
I don't use size() in my software. I keep my own count of what is in the collection with an AtomicInteger. If count.get() < max, I can add. Being a little over max is ok for my usage. You can use a lock on count to force compliance.
The first thread is filling a collection continuously with objects. A second thread needs to iterate over these objects, but it will not change the collection.
Currently I use Collection.synchronized for making it thread-safe, but is there a fast way to doing it?
Update
It's simple: The first thread (ui) continuously writes the mouse position to the ArrayList, as long as the mousebutton is pressed down. The second thread (render) draws a line based on the list.
Use java.util.concurrent.ArrayBlockingQueue.ArrayBlockingQueue implementation of BlockingQueue. It perfectly suits your needs.
It is perfectly suited for producer-consumer cases as that is one in yours.
You can also configure access policy. Javadoc explains access policy like this:
Fair if true then queue accesses for threads blocked on insertion or removal, are processed in FIFO order; if false the access order is unspecified.
Even if you synchronize the list, it's not necessarily thread-safe while iterating over it, so make sure you synchronize on it:
synchronized(synchronizedList) {
for (Object o : synchronizedList) {
doSomething()
}
}
Edit:
Here's a very clearly written article on the matter:
http://java67.blogspot.com/2014/12/how-to-synchronize-arraylist-in-java.html
As mentioned in comments, you need explicit synchronization on this list, because iteration is not atomic:
List<?> list = // ...
Thread 1:
synchronized(list) {
list.add(o);
}
Thread 2:
synchronized(list) {
for (Object o : list) {
// do actions on object
}
}
There are 3 options which I can currently think of to handle concurrency in ArrayList:-
Using Collections.synchronizedList(list) - currently you are using it.
CopyOnWriteArrayList - behaves much like ArrayList class, except that when the list is modified, instead of modifying the underlying array, a new array in created and the old array is discarded. It will be slower than 1.
Creating custom ArrayList class using ReentrantReadWriteLock. You can create a wrapper around ArrayList class. Use read lock when reading/iterating/looping and use write lock when adding elements in array.
For e.g:-
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteList<E> {
private final List<E> list;
private ReadWriteLock lock = new ReentrantReadWriteLock();
private final Lock r =lock.readLock();
private final Lock w =lock.writeLock();
public ReadWriteList(List<E> list){
this.list=list;
}
public boolean add(E e){
w.lock();
try{
return list.add(e);
}
finally{
w.unlock();
}
}
//Do the same for other modification methods
public E getElement(int index){
r.lock();
try{
return list.get(index);
}
finally{
r.unlock();
}
}
public List<E> getList(){
r.lock();
try{
return list;
}
finally{
r.unlock();
}
}
//Do the same for other read methods
}
If you're reading far more often than writing, you can use CopyOnWriteArrayList
Rather than a List will a Set suit your needs?
If so, you can use Collections.newSetFromMap(new ConcurrentHashMap<>())
I have a multithreaded application, where a shared list has write-often, read-occasionally behaviour.
Specifically, many threads will dump data into the list, and then - later - another worker will grab a snapshot to persist to a datastore.
This is similar to the discussion over on this question.
There, the following solution is provided:
class CopyOnReadList<T> {
private final List<T> items = new ArrayList<T>();
public void add(T item) {
synchronized (items) {
// Add item while holding the lock.
items.add(item);
}
}
public List<T> makeSnapshot() {
List<T> copy = new ArrayList<T>();
synchronized (items) {
// Make a copy while holding the lock.
for (T t : items) copy.add(t);
}
return copy;
}
}
However, in this scenario, (and, as I've learned from my question here), only one thread can write to the backing list at any given time.
Is there a way to allow high-concurrency writes to the backing list, which are locked only during the makeSnapshot() call?
synchronized (~20 ns) is pretty fast and even though other operations can allow concurrency, they can be slower.
private final Lock lock = new ReentrantLock();
private List<T> items = new ArrayList<T>();
public void add(T item) {
lock.lock();
// trivial lock time.
try {
// Add item while holding the lock.
items.add(item);
} finally {
lock.unlock();
}
}
public List<T> makeSnapshot() {
List<T> copy = new ArrayList<T>(), ret;
lock.lock();
// trivial lock time.
try {
ret = items;
items = copy;
} finally {
lock.unlock();
}
return ret;
}
public static void main(String... args) {
long start = System.nanoTime();
Main<Integer> ints = new Main<>();
for (int j = 0; j < 100 * 1000; j++) {
for (int i = 0; i < 1000; i++)
ints.add(i);
ints.makeSnapshot();
}
long time = System.nanoTime() - start;
System.out.printf("The average time to add was %,d ns%n", time / 100 / 1000 / 1000);
}
prints
The average time to add was 28 ns
This means if you are creating 30 million entries per second, you will have one thread accessing the list on average. If you are creating 60 million per second, you will have concurrency issues, however you are likely to be having many more resourcing issue at this point.
Using Lock.lock() and Lock.unlock() can be faster when there is a high contention ratio. However, I suspect your threads will be spending most of the time building the objects to be created rather than waiting to add the objects.
You could use a ConcurrentDoublyLinkedList. There is an excellent implementation here ConcurrentDoublyLinkedList.
So long as you iterate forward through the list when you make your snapshot all should be well. This implementation preserves the forward chain at all times. The backward chain is sometimes inaccurate.
First of all, you should investigate if this really is too slow. Adds to ArrayLists are O(1) in the happy case, so if the list has an appropriate initial size, CopyOnReadList.add is basically just a bounds check and an assignment to an array slot, which is pretty fast. (And please, do remember that CopyOnReadList was written to be understandable, not performant.)
If you need a non-locking operation, you can have something like this:
class ConcurrentStack<T> {
private final AtomicReference<Node<T>> stack = new AtomicReference<>();
public void add(T value){
Node<T> tail, head;
do {
tail = stack.get();
head = new Node<>(value, tail);
} while (!stack.compareAndSet(tail, head));
}
public Node<T> drain(){
// Get all elements from the stack and reset it
return stack.getAndSet(null);
}
}
class Node<T> {
// getters, setters, constructors omitted
private final T value;
private final Node<T> tail;
}
Note that while adds to this structure should deal pretty well with high contention, it comes with several drawbacks. The output from drain is quite slow to iterate over, it uses quite a lot of memory (like all linked lists), and you also get things in the opposite insertion order. (Also, it's not really tested or verified, and may actually suck in your application. But that's always the risk with using code from some random dude on the intertubes.)
Yes, there is a way. It is similar to the way ConcurrentHashMap made, if you know.
You should make your own data structure not from one list for all writing threads, but use several independent lists. Each of such lists should be guarded by it's own lock. .add() method should choose list for append current item based on Thread.currentThread.id (for example, just id % listsCount). This will gives you good concurrency properties for .add() -- at best, listsCount threads will be able to write without contention.
On makeSnapshot() you should just iterate over all lists, and for each list you grab it's lock and copy content.
This is just an idea -- there are many places to improve it.
You can use a ReadWriteLock to allow multiple threads to perform add operations on the backing list in parallel, but only one thread to make the snapshot. While the snapshot is being prepared all other add and snapshot request are put on hold.
A ReadWriteLock maintains a pair of associated locks, one for
read-only operations and one for writing. The read lock may be held
simultaneously by multiple reader threads, so long as there are no
writers. The write lock is exclusive.
class CopyOnReadList<T> {
// free to use any concurrent data structure, ConcurrentLinkedQueue used as an example
private final ConcurrentLinkedQueue<T> items = new ConcurrentLinkedQueue<T>();
private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
private final Lock shared = rwLock.readLock();
private final Lock exclusive = rwLock.writeLock();
public void add(T item) {
shared.lock(); // multiple threads can attain the read lock
// try-finally is overkill if items.add() never throws exceptions
try {
// Add item while holding the lock.
items.add(item);
} finally {
shared.unlock();
}
}
public List<T> makeSnapshot() {
List<T> copy = new ArrayList<T>(); // probably better idea to use a LinkedList or the ArrayList constructor with initial size
exclusive.lock(); // only one thread can attain write lock, all read locks are also blocked
// try-finally is overkill if for loop never throws exceptions
try {
// Make a copy while holding the lock.
for (T t : items) {
copy.add(t);
}
} finally {
exclusive.unlock();
}
return copy;
}
}
Edit:
The read-write lock is so named because it is based on the readers-writers problem not on how it is used. Using the read-write lock we can have multiple threads achieve read locks but only one thread achieve the write lock exclusively. In this case the problem is reversed - we want multiple threads to write (add) and only thread to read (make the snapshot). So, we want multiple threads to use the read lock even though they are actually mutating. Only thread is exclusively making the snapshot using the write lock even though snapshot only reads. Exclusive means that during making the snapshot no other add or snapshot requests can be serviced by other threads at the same time.
As #PeterLawrey pointed out, the Concurrent queue will serialize the writes aqlthough the locks will be used for as minimal a duration as possible. We are free to use any other concurrent data structure, e.g. ConcurrentDoublyLinkedList. The queue is used only as an example. The main idea is the use of read-write locks.
i have created synchronized arrayList like this
import java.text.SimpleDateFormat;
import java.util.*;
class HelloThread
{
int i=1;
List arrayList;
public void go()
{
arrayList=Collections.synchronizedList(new ArrayList());
Thread thread1=new Thread(new Runnable() {
public void run() {
while(i<=10)
{
arrayList.add(i);
i++;
}
}
});
thread1.start();
Thread thred2=new Thread(new Runnable() {
public void run() {
while(true)
{
Iterator it=arrayList.iterator();
while(it.hasNext())
{
System.out.println(it.next());
}
}
}
});
thred2.start();
}
}
public class test
{
public static void main(String[] args)
{
HelloThread hello=new HelloThread();
hello.go();
}
}
but getting exception like this
Exception in thread "Thread-1" java.util.ConcurrentModificationException
anything wrong in my approach ?
Iterator of synchronizedList is not (and can't be) synchronized, you need to synchronize on the list manually while iterating (see javadoc):
synchronized(arrayList) {
Iterator it=arrayList.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
}
Another approach is to use a CopyOnWriteArrayList instead of Collections.synchronizedList(). It implements a copy-on-write semantic and therefore doesn't require synchronization.
Consider using a CopyOnWriteArrayList which is thread-safe. Every time you add an item, a fresh copy of the underlying array is created. However, the iterator will not reflect additions to the list since the iterator was created, but is guaranteed not to throw ConcurrentModificationException.
arrayList=new CopyOnWriteArrayList();
Other answers have identified the problem:
The iterators for synchronized collections are not synchronized. In fact, they are simply the iterators returned by the collection objects inside the wrapper classes.
Many collection classes (including ArrayList) use a fail-fast mechanism to detect concurrent modifications during iteration. This behavior is clearly documented in the javadocs for the respective classes. This is what you are seeing.
Not all collection classes do this. For example, many of the java.util.Concurrent... collection classes allow concurrent modification during iteration, but relax the semantics of the iteration sequence so that the results of the modifications may or may not be apparent in the objects returned by the iterator.
The javadoc for the Collections.synchronizedList() explains how to synchronize the iterator. Basically you do this:
List list = Collections.synchronizedList(new ArrayList());
...
synchronized (list) {
Iterator i = list.iterator(); // Must be in synchronized block
while (i.hasNext())
foo(i.next());
}
(Aside: normally it is not safe to assume that doing something like this would work. In theory, the synchronized list could use a private lock object, and the synchronized statement would not lock out concurrent modifications. However the javadocs say that this is what to do in this case ... so it is safe.)
The problem with doing that is that locking the collection creates a potential concurrency bottleneck. The alternative to is to use a copy-on-write data structure that internally makes a copy of the relevant parts of the collection. This approach means that an iterator sees sees a snapshot of the collection. Modifications may be made to the collection concurrent with an iteration, but the iterator does not see them. The problem with copy-on-write is that modifications are potentially a lot more expensive.
Ultimately, you need to balance the characteristics and costs of the different collection types wrt concurrent modification versus your actual requirements. Can you get away with the iterator not seeing all concurrent modifications?
The java.util.ConcurrentModificationException occurs when you manipulate (add,remove) a collection while iterating over the same collection.
You probably want to consume the create entries in your second thread while after they have been created by your first thread. So you could use ArrayLists get( index ) and size() for control
As Spike said, you can't modify a collection while iterating it. However, I think the solution is to lock the list while iterating.
class HelloThread
{
int i=1;
List arrayList;
public void go()
{
arrayList=Collections.synchronizedList(new ArrayList());
Thread thread1=new Thread(new Runnable() {
public void run() {
while(i<=10)
{
synchronized(someLock) {
arrayList.add(i);
}
i++;
}
}
});
thread1.start();
Thread thred2=new Thread(new Runnable() {
public void run() {
while(true)
{
synchronized(someLock) {
Iterator it=arrayList.iterator();
while(it.hasNext())
{
System.out.println(it.next());
}
}
}
}
});
thred2.start();
}
}
public class test
{
public static void main(String[] args)
{
HelloThread hello=new HelloThread();
hello.go();
}
}
I'm not sure what you're trying to do, so I hope this doesn't break the functionality of your code.
You may not modify a Collection that you are iterating. You can work around this by accessing the array entries by index, not through an Iterator. I can provide more advice if you tell me the problem that you are trying to solve with this code.
Let's take a normal list (implemented by the ArrayList class) and make it synchronized. This is shown in the SynchronizedArrayList class.
We pass the Collections.synchronizedList method a new ArrayList of Strings. The method returns a synchronized List of Strings.
//Here is SynchronizedArrayList class
package com.mnas.technology.automation.utility;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.apache.log4j.Logger;
/**
*
* #author manoj.kumar
* #email kumarmanoj.mtech#gmail.com
*
*/
public class SynchronizedArrayList {
static Logger log = Logger.getLogger(SynchronizedArrayList.class.getName());
public static void main(String[] args) {
List<String> synchronizedList = Collections.synchronizedList(new ArrayList<String>());
synchronizedList.add("Aditya");
synchronizedList.add("Siddharth");
synchronizedList.add("Manoj");
// when iterating over a synchronized list, we need to synchronize access to the synchronized list
synchronized (synchronizedList) {
Iterator<String> iterator = synchronizedList.iterator();
while (iterator.hasNext()) {
log.info("Synchronized Array List Items: " + iterator.next());
}
}
}
}
Notice that when iterating over the list, this access is still done using a synchronized block that locks on the synchronizedList object.
In general, iterating over a synchronized collection should be done in a synchronized block
ArrayList is non-synchronized collection and should not be used in concurrent environment without explicit synchronization. To synchronize ArrayList, we can use two methods provided by JDK
Collections.synchronizedList() method – It returns synchronized list backed by the specified list. It is recommended that we should manually synchronize on the returned list when traversing it via Iterator, Spliterator or Stream. Else it may result in non-deterministic behavior. No explicit synchronization is needed to add, remove elements from synchronized arraylist
CopyOnWriteArrayList class – It is a thread-safe variant of ArrayList.
Since you are using iterator without explicit synchronization you are getting the error