Razvi
Razvi

Reputation: 2818

Java collection to allow adding and removing while iterating

I am interested if there is any framework that implements a collection that would have the following behavior.


Suppose it initially contains: [1, 2, 3]

Same should apply for removal of elements. If I remove 3 instead of adding, the second iterator should give me [1, 2] while the first one will still give me 3 and the end.


So when I get and iterator I want it to give me the collection I had when I created the iterator (even if I iterate it later, on I iterate a bit and continue later), when I reset the iterator, it gets garbage collected it will update to the latest versions and I should be able to have multiple iterator instances created at different times that will give different versions depending on the contents of the array when the iterator was created.

I would need it to work well with multiple threads and preferable have an efficient implementation.

Does anyone know of any implementation of such a collection, or do I have to implement it myself?

Upvotes: 6

Views: 1432

Answers (5)

Francisco Spaeth
Francisco Spaeth

Reputation: 23903

You could make use of java.util.concurrent.CopyOnWriteArrayList<E>

According documentation:

A thread-safe variant of ArrayList in which all mutative operations (add, set, and so on) are implemented by making a fresh copy of the underlying array.

Its costly, but thread safe.

This is ordinarily too costly, but may be more efficient than alternatives when traversal operations vastly outnumber mutations, and is useful when you cannot or don't want to synchronize traversals, yet need to preclude interference among concurrent threads. The "snapshot" style iterator method uses a reference to the state of the array at the point that the iterator was created.

As the iteration occurs over a kind of snapshot, the operations (remove, set, and add) on Iterator itself are not supported.

Upvotes: 3

JIV
JIV

Reputation: 823

javolution have threadsafe FastMap

Upvotes: 0

assylias
assylias

Reputation: 328629

What you describe looks very similar to how CopyOnWriteArrayList works:

  • once you start iterating, you can change the collection (including from another thread) without affecting the iteration
  • if you create a new iterator it will be based on the collection at the creation time
  • it is thread safe

Simple example below with the following output:

Iterator 1 - 1
4 has been added
Iterator 2 - 1
Iterator 2 - 2
Iterator 2 - 3
Iterator 2 - 4
Iterator 1 - 2
Iterator 1 - 3

public static void main(String[] args) throws InterruptedException {
    final List<Integer> list = new CopyOnWriteArrayList<Integer>();
    list.addAll(Arrays.asList(1, 2, 3));
    new Thread(new Runnable() {

        @Override
        public void run() {
            for (Integer i : list) {
                System.out.println("Iterator 1 - " + i);
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {}
            }
        }
    }).start();
    Thread.sleep(10);
    list.add(4);
    System.out.println("4 has been added");
    for (Integer i : list) {
        System.out.println("Iterator 2 - " + i);
    }

}

Upvotes: 6

gkamal
gkamal

Reputation: 21000

You can use the ImmutableCollections from the guava library.

The returned ImmutableList is frequently -- not always, but frequently -- a constant-overhead view, rather than an explicit copy. That said, it's often smarter than your average List -- for example, it'll use the efficient contains methods of the backing collection.

Upvotes: 3

Louis Wasserman
Louis Wasserman

Reputation: 198133

java.util.concurrent.CopyOnWriteArrayList will behave like this, except that no Java collection has "resetting" of iterators -- but getting a new iterator instead of resetting has the effect you request here.

Upvotes: 7

Related Questions