How to return a thread safe/immutable Collection in Java?
In the project I am coding, I need to return a thread safe and immutable view from a function. However, I am unsure of this.开发者_JS百科 Since synchronizedList
and unmodifiableList
just return views of a list, I don't know if
Collections.synchronizedList(Collections.unmodifiableList(this.data));
would do the trick.
Could anyone tell me if this is correct, and in case it is not, are there any situations that this would likely to fail?
Thanks for any inputs!
I find this to be a real gap in the JDK. Fortunately, a team over a Google, led by Java Collections designer Joshua Bloch, have created a library that includes truly immutable collections.
ImmutableList in particular is the implementation you're looking for. Here is a quick sketch of some of the features of Guava's ImmutableCollections.
I think unmodifiable is sufficient. You can't write to it, which is what causes problems for multi-threaded access. It's read-only, so the additional step of synchronizing seems unnecessary to me.
Best to check out the source code when there are questions like this. Looks like it returns an UnmodifiableList
:
/**
* @serial include
*/
static class UnmodifiableList<E> extends UnmodifiableCollection<E>
implements List<E> {
static final long serialVersionUID = -283967356065247728L;
final List<? extends E> list;
UnmodifiableList(List<? extends E> list) {
super(list);
this.list = list;
}
public boolean equals(Object o) {return o == this || list.equals(o);}
public int hashCode() {return list.hashCode();}
public E get(int index) {return list.get(index);}
public E set(int index, E element) {
throw new UnsupportedOperationException();
}
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
public E remove(int index) {
throw new UnsupportedOperationException();
}
public int indexOf(Object o) {return list.indexOf(o);}
public int lastIndexOf(Object o) {return list.lastIndexOf(o);}
public boolean addAll(int index, Collection<? extends E> c) {
throw new UnsupportedOperationException();
}
public ListIterator<E> listIterator() {return listIterator(0);}
public ListIterator<E> listIterator(final int index) {
return new ListIterator<E>() {
ListIterator<? extends E> i = list.listIterator(index);
public boolean hasNext() {return i.hasNext();}
public E next() {return i.next();}
public boolean hasPrevious() {return i.hasPrevious();}
public E previous() {return i.previous();}
public int nextIndex() {return i.nextIndex();}
public int previousIndex() {return i.previousIndex();}
public void remove() {
throw new UnsupportedOperationException();
}
public void set(E e) {
throw new UnsupportedOperationException();
}
public void add(E e) {
throw new UnsupportedOperationException();
}
};
}
Collections.unmodifiableList(this.data)
Statement above will do, as it will return a view. Any modification attempts on this view will result of UnsupportedOperationException
being thrown. Below are excerpt of Collections#unmodifiableList
documentation.
Returns an unmodifiable view of the specified list. This method allows modules to provide users with "read-only" access to internal lists. Query operations on the returned list "read through" to the specified list, and attempts to modify the returned list, whether direct or via its iterator, result in an UnsupportedOperationException.
......
java 8 java.util.Collections javadoc
copyOf
Yes, now built into Java 10 and later.
List.copyOf
Set.copyOf
Map.copyOf
Each of these returns a separate collection of the objects found in the original. The returned collection is not a view onto the original, as is the case with the Collections.unmodifiable…
utility class methods.
The copyOf
methods are copying the references (pointers), not the objects. So, not much memory is involved.
Java 9+ ImmutableCollections are thread safe. For example, List.of, Map.of, Map.copyOf(Java 10+)
...
According to oracle doc,
One advantage of an immutable collection is that it is automatically thread safe. After you create a collection, you can hand it to multiple threads, and they will all see a consistent view.
Read more at: oracle docs
These views won't return you truly thread-safe collections. There is always the possibility that someone will modify either the backing collection, or the elements within the collection.
To solve this, you need to use immutable collections and immutable elements. Then, thread-safety happens as a result.
Clojure contains such immutable (or persistent) collections.
Put simply, adding or removing new elements returns a new collection, which in general does reuse large parts of the old collection through clever use of Trie-type data structures.
On their own, these are a poor fit for using in straight Java.
Pure4j is an attempt to port these (and the immutable/value based style advocated by Clojure) to the Java language. It might be what you're after.
Disclaimer: I am the developer of Pure4J
精彩评论