I have created a hashmap outside my mutithreading code. There are going to be no changes in this hasmap later.
After this, I am starting two threads which will both be reading from this hashmap(yes, only read operations). If thread1 is reading from my hashmap object , can thread 2 also read at the same time? Or do I need a Concurrenthashmap or any other version of Map?
If thread1 is reading from my hashmap object, can thread 2 also read
at the same time?
If you are sure that there are no write operations then you need not use Synchronization options at all, Go for a normal version of Map.
You can also use Immutable Map
A Map whose contents will never change, with many other important
properties detailed at ImmutableCollection
No you don't need concurrent Hash maps..but only since you don not do any modifications. You can read the same without any problem.
If you required only read operation then no need to use synchronization.If you are not doing any write after creation make it immutable so no body can change it .No need for synchronization.
Related
A quick question about ConcurrentHashMap:
public Map<String, String> getA(){
get something from db in a HashMap lets call it x
....
do some operations in on x
....
put the result in ConcurrentHashMap lets call it A
.....
return A
}
Does it make sense to have a ConcurrentHashMap or should I go with a HashMap?
1.HashMap
2.ConsurentHashMap
If you are on different threads or otherwise the data will be operated on at the same time (multithreaded delegate or the alike) , yes, use ConcurrentHashMap. Otherwise, HashMap should do (given the information you've provided).
Based on reading your pseudo code, I get the impression that you are not working on different threads and therefore HashMap should suffice.
You might do better wrapping it in Collections.unmodifiableMap() if you don't want to worry about the clients of this method getting into race conditions when modifying/reading the map.
Say I have a hash map and multiple threads. If I have a synchronized method that adds to the hash map, how would I make it possible that two different threads can put different keys simultaneously (concurrently) into the hash map?
My current implementation is a synchronized method. Would this allow two different threads to put two different keys simultaneously into the hash map?
I am using a regular hash map, not Java's concurrent hash map. I am not allowed to use a concurrent hash map.
EDIT:
I think I found a solution! I think I may have miswrote this post. Let's say that the hash map is initialized as a Integer as its key and a LinkedList as its value. In order to put a totally new key, I realize that the whole hash map has to be synchronized (i.e. locked). However, if I am trying to add another String into an already contained key's corresponding LinkedList, I can just synchronize the hash map's get method. I think this will allow multiple threads to simultaneously (concurrently) add to the LinkedLists of different, already contained keys. Please let me know if I'm wrong.
Here's a concrete example. I have a hash map hashMap that uses an Integer as its key and a LinkedList as its value. The keys 5, and 10 are already in the hash map. The key 5 contains a LinkedList of Joey, Joe, Kerry. The key 10 contains the LinkedList of Jerry, Mary, Tim. I have two threads t1 and t2. t1 wants to add Moe to the LinkedList corresponding to key 5. t2 wants to add Harry to the LinkedList corresponding to key 10. Both will be concurrently added to the hash map, since the hash map's value is only locked.
My current implementation is a synchronized method. Would this allow two different threads to put two different keys simultaneously into the hash map?
No. Only a ConcurrentHashMap or a specifically designed concurrent map would support this safely, so it's impossible for you to put two keys simultaneously into the same map from two threads.
how would I make it possible that two different threads can put different keys simultaneously (concurrently) into the hash map?
You cannot, without using ConcurrentHashMap, another ConcurrentMap implementation, or implementing your own.
The easiest answer is to use a ConcurrentHashMap, which does exactly what you're looking for.
If you can't do that (I see you edited your post after I answered), then you'll have to duplicate the same thing that ConcurrentHashMap does. No, simply synchronizing the method of a HashMap will not allow two threads to add a key-value pair at the same time, they have to wait and go one at a time.
The answer to your question is NO. Because synchronized block forces every tread to wait in the single queue. With ConcurrentHashMap you have more chances for simultaneously add, because it locks only basket where element will be inserted instead of locking whole HashMap.
However, if I am trying to add another String into an already contained key's corresponding LinkedList, I can just synchronize the hash map's get method. I think this will allow multiple threads to simultaneously (concurrently) add to the LinkedLists of different, already contained keys.
Read-only access to a HashMap is safe: you can have multiple threads call the get method with no synchronization at all and nothing breaks. If the linked lists are not shared between threads you don't need synchronization either. To be sure the threads never share a list the map key should be something specific to the thread, like an object created locally or the thread ID.
What's not safe is to let another thread modify a map or a list concurrently with a read or write. This is the use case for a read-write lock: it allows multiple concurrent reads but writes have to be exclusive.
What is the best way to implement synchronization of a linkedhashmap externally, without using Collections.synchronizedMap
When Collections.synchronizedMap is used entire datastructure is locked, so performance is hugely impacted in a bad way.
What is the best way to lock only required part of datastructure. e.g. If thread is accessing key (K1), it should lock only Key(K1) and Value(v1) part of the datastructure
You can't get a fine-grained-locking, FIFO-eviction concurrent map from the built-in Java implementations.
Check out Guava's Cache or the open-source ConcurrentLinkedHashMap project.
I think you may want to synchronize the subsequent operation you do, just on the value coming from the map:
Object value = map.get(key);
synchronized(value) {
doSomethingWith(value);
}
Synchronizing to values get from the Map, makes sense, since they can be shared and accessed concurrently; the example I posted above should do what you need. That should be enough.
By the way you can also synchronize on the key doing two nested synchronized blocks:
synchronized(key) {
Object value = map.get(key);
synchronized(value) {
doSomethingWith(value);
}
}
The key is -usually- just used to access the object (by hashing). Keys are matched by hash value, so it doesn't make full sense to me to synchronize over the key.
Or, maybe you can subclass ConcurrentHashMap adding what is missing from LinkedHashMap.
Louis Wasserman's suggestion is probably the best because it gives you a lot of useful functionality. However, even if you lock on the entire map, you have to be hitting it really, really hard to make that a bottleneck (as in, your code is mostly doing read/write on the map). If you don't need the additional functionality of Guava's Cache, a synchronized map could be simpler & better. You could also use a ReadWriteLock if you mostly read from the map.
Best option would be to use java.util.concurrent.ConcurrentHashMap .
I can't see how it would be possible to externally lock only parts of zour Map, since you cannot control what shared datastructures are accessed internally by a call to any of the maps function.
If you don't need a LinkedHaspMap, use a ConcurrentHashMap from the java.util.concurrent package.
It is specifically designed for both speed and thread safety. It uses the minimal possible locking to achieve its thread safety.
An insertion in a HashMap, or LinkedHashMap, can cause a rehash because it increases the ratio between the size and the number of buckets. Having two or more threads rehash simultaneously would be a disaster.
Even if you are only doing a get, another thread may be removing an entry from the same bucket, so you are scanning a linked list that is being modified under you. You could also have two or more threads appending to the main linked list at the same time.
If you can do without the linking, use java.util.concurrent.ConcurrentHashMap, as already suggested.
If I do the following.
Create a HashMap (in a final field)
Populate HashMap
Wrap HashMap with unmodifiable wrapper Map
Start other threads which will access but not modify the Map
As I understand it the Map has been "safely published" because the other threads were started after the Map was fully populated so I think it is ok to access the Map from multiple threads as it cannot be modified after this point.
Is this right?
This is perfectly fine concerning the map itself. But you need to realize the making the map unmodifiable will only make the map itself unmodifiable and not its keys and values. So if you have for example a Map<String, SomeMutableObject> such as Map<String, List<String>>, then threads will still be able to alter the value by for example map.get("foo").add("bar");. To avoid this, you'd like to make the keys/values immutable/unmodifiable as well.
As I understand it the Map has been "safely published" because the other threads were started after the Map was fully populated so I think it is ok to access the Map from multiple threads as it cannot be modified after this point.
Yes. Just make sure that the other threads are started in a synchronized manner, i.e. make sure you have a happens-before relation between publishing the map, and starting the threads.
This is discussed in this blog post:
[...] This is how Collections.unmodifiableMap() works.
[...]
Because of the special meaning of the keyword "final", instances of this class can be shared with multiple threads without using any additional synchronization; when another thread calls get() on the instance, it is guaranteed to get the object you put into the map, without doing any additional synchronization. You should probably use something that is thread-safe to perform the handoff between threads (like LinkedBlockingQueue or something), but if you forget to do this, then you still have the guarantee.
In short, no you don't need the map to be thread-safe if the reads are non-destructive and the map reference is safely published to the client.
In the example there are two important happens-before relationships established here. The final-field publication (if and only if the population is done inside the constructor and the reference doesn't leak outside the constructor) and the calls to start the threads.
Anything that modifies the map after these calls wrt the client reading from the map is not safely published.
We have for example a CopyOnWriteMap that has a non-threadsafe map underlying that is copied on each write. This is as fast as possible in situations where there are many more reads than writes (caching configuration data is a good example).
That said, if the intention really is to not change the map, setting an immutable version of the map into the field is always the best way to go as it guarantees the client will see the correct thing.
Lastly, there are some Map implementations that have destructive reads such as a LinkedHashMap with access ordering, or a WeakHashMap where entries can disappear. These types of maps must be accessed serially.
You are correct. There is no need to ensure exclusive access to the data structure by different threads by using mutex'es or otherwise since it's immutable. This usually greatly increases performance.
Also note that if you only wrap the original Map rather than creating a copy, ie the unmodifiable Map delegates method calls further to the inner HashMap, modifying the underlying Map may introduce race condition problems.
Immutable map is born to thread-safe. You could use ImmutableMap of Guava.
my code throw follow exception:
java.util.ConcurrentModificationException
at java.util.LinkedList$ListItr.checkForComodification(LinkedList.java:761)
at java.util.LinkedList$ListItr.next(LinkedList.java:696)
at java.util.AbstractCollection.addAll(AbstractCollection.java:305)
at java.util.LinkedHashSet.<init>(LinkedHashSet.java:152)
...
I want a ConcurrentLinkedHashSet to fix it,
but I only found ConcurrentSkipListSet in java.util.concurrent,this is TreeSet, not LinkedHashSet
any easies way to get ConcurrentLinkedHashSet in JDK6.0?
thanks for help :)
A ConcurrentModificationException has nothing to do with concurrency in the form you're thinking of. This just means that while iterating over the Collection, someone (probably your own code - that happens often enough ;) ) is changing it, i.e. adding/removing some values.
Make sure you're using the Iterator to remove values from the collection and not the collection itself.
Edit: If really another thread is accessing the Collection at the same time, the weak synchronization you get from the standard library is useless anyhow, since you've got to block the Collection for the whole duration of the operation not just for one add/remove! I.e. something like
synchronize(collection) {
// do stuff here
}
You can always create a synchronized collection with Collections.synchronizedMap(myMap);. However, trying to alter the map while you're iterating (which I'm assuming is the cause of your error) will still be a problem.
From the docs for synchronizedMap:
Returns a synchronized (thread-safe) map backed by the specified map. In order to guarantee serial access, it is critical that all access to the backing map is accomplished through the returned map.
It is imperative that the user
manually synchronize on the returned
map when iterating over any of its
collection views ... Failure to follow
this advice may result in
non-deterministic behavior.
This is because
normally a concurrent collection is really guaranteeing atomic get/put but is not locking the entire collection during iteration, which would be too slow. There's no concurrency guarantee over iteration, which is actually many operations against the map.
it's not really concurrency if you're altering during iteration, as it's impossible to determine correct behavior - for example, how do you reconcile your iterator returning hasNext == true with deleting a (possibly the next value) from the collection?
There is ConcurrentLinkedHashMap - https://code.google.com/p/concurrentlinkedhashmap/
You can create Set out of it with java.util.Collections.newSetFromMap(map)
Unfortunately not. You could implement your own, wrapping a ConcurrentHashMap and a ConcurrentLinkedQueue, but this wouldn't allow you to remove values easily (removal would be O(N), since you'd have to iterate through everything in the queue) ...
What are you using the LinkedHashSet for though? Might be able to suggest alternatives...