Is static initialized unmodifiableCollection.get guaranteed immutable?
For:
static final Map FOO = Collections.unmodifiableMap(new HashMap());
Can multiple threads use method get and not run into problems?
Even through items in FOO cannot be added/removed, what's stopping the get method from manipulating FOO's internal stat开发者_运维问答e for caching purposes, etc. If the internal state is modified in any way then FOO can't be used concurrently. If this is the case, where are the true immutable collections in java?
Given the specific example:
static final Map FOO = Collections.unmodifiableMap(new HashMap());
Then FOO will be immutable. It will also never have any elements. Given the more general case of:
static final Map BAR = Collections.unmodifiableMap(getMap());
Then whether or not this is immutable is entirely dependent on whether or not someone else can get to the underlying Map, and what type of Map it is. For example, if it is a LinkedHashMap then the underlying linked list could be modified by access order, and could change by calling get(). The safest way (using non-concurrent classes) to do this would be:
static final Map BAR = Collections.unmodifiableMap(new HashMap(getMap()));
The javadocs for HashMap imply that so long as you make no structural changes to the map, then it is safe to use it concurrently, so this should be safe for any of the accessors that you can use, that is getting the various sets and iterating over them and get() should then be safe.
If you can use the concurrent classes, then you could also do:
static final Map BAR = Collections.unmodifiableMap(new ConcurrentHashMap(getMap());
This will be explicitly safe to use from multiple threads, since ConcurrentHashMap is explicitly multi-thread access safe. The internal state might be mutable, but the externally visible state will not be, and since the class is guaranteed to be threadsafe, we can safely consider it to be externally immutable.
At the risk of sounding like I'm on an advertising spree, use the Google Immutable Collections and be done with it.
Actually a good question. Think WeakHashMap
- that can change without having a mutation operation called on it. LinkedHashMap
in access-order mode is much the same.
The API docs for HashMap
state:
Note that this implementation is not synchronized. If multiple threads access a hash map concurrently, and at least one of the threads modifies the map structurally, it must be synchronized externally. (A structural modification is any operation that adds or deletes one or more mappings; merely changing the value associated with a key that an instance already contains is not a structural modification.)
Presumably that should be if and only if. That means that get
does not need to be synchronised if the HashMap
is 'effectively immutable'.
There is no true immutable map in Java SDK. All of the suggested Maps by Chris are only thread safe. The unmodifiable Map is not immutable either since if the underlying Map changed there will ConcurrentModificationException
as well.
If you want the truly immutable map, use ImmutableMap from Google Collections / Guava.
I would suggest for any threaded operation to use ConcurrentHashMap or HashTable, both are thread-safe.
Whether a getter on the returned map happens to twiddle with some internal state is unimportant, as long as the object honors its contract (which is to be a map that cannot be modified). So your question is "barking up the wrong tree".
You are right to be cautious of UnmodifiableMap, in the case where you do not have ownership and control over the map it wraps. For example
Map<String,String> wrapped = new HashMap<String,String>();
wrapped.add("pig","oink");
Map<String,String> wrapper = Collections.unmodifiableMap(wrapped);
System.out.println(wrapper.size());
wrapper.put("cow", "moo"); // throws exception
wrapped.put("cow", "moo");
System.out.println(wrapper.size()); // d'oh!
精彩评论