I have a singleton class, that has a map which can be accessed by multiple threads at the same time. Could somebody please check the code below and tell me if its thread safe?
(note: I dont plan to use ConcurrentHashMap, and the printMap method is called only seldom.)
public class MySingleton{
private Map<String,String> cache = Collections.synchronizedMap(
new LinkedHashMap<String,String>());
public String getValue(String key){
return cache.get(key)
}
public void setValue(String key, String value){
cache.put(key, value);
}
public void printMap(){
synchronized(cache){
for(Entry<String,String> entry: cache.entrySet()){
println('key: '+entry.getKey()+', value: ' + value);
}
}
}
}
My test is working... but i am doubting if this code is good enough to be called 'thread safe'.
points that I considered:
The readValue and putValue methods don't need to have a 'synchronized' block since i am using a synchronizedMap
printMap should have the synchronized block, since the javadoc for says that we should synchronize the Map instance before each iteration.
http://download.oracle.com/javase/1.5.0/docs/api/java/util/Collections.html#synchronizedMap%28java.util.Map%29
Any help is appreciated.
Yes, that's okay. The key thing is that while you're iterating, nothing will be able to modify the map because cache.put will end up synchronizing on cache anyway.
Personally I'd rather make that explicit, by using a "normal" hashmap and synchronizing on the same object (whether the map or something else) from all three methods - but what you've got should be fine.
(Alternatively, you could use ConcurrentHashMap to start with. It's worth at least looking at that.)
Yes it is thread safe. Each access to the cache is synchronized (by the synchronizedMap for get and set and by an explicit sync block for the printMap)
Yes, this class is thread-safe.
Though note that even a thread-safe class requires safe publication to be used really safely (without safe publication nothing guarantees that other threads can't see cache in non-initialized state, i.e. null).
But in this case you can eliminate a need in safe publication by making your class immutable (final keyword guarantees that other threads can't see null in cache):
private final Map<String,String> cache = Collections.synchronizedMap( new LinkedHashMap<String,String>());
Related
Back to concurrency. By now it is clear that for the double checked locking to work the variable needs to be declared as volatile. But then what if double checked locking is used as below.
class Test<A, B> {
private final Map<A, B> map = new HashMap<>();
public B fetch(A key, Function<A, B> loader) {
B value = map.get(key);
if (value == null) {
synchronized (this) {
value = map.get(key);
if (value == null) {
value = loader.apply(key);
map.put(key, value);
}
}
}
return value;
}
}
Why does it really have to be a ConcurrentHashMap and not a regular HashMap? All map modification is done within the synchronized block and the code doesn't use iterators so technically there should be no "concurrent modification" problems.
Please avoid suggesting the use of putIfAbsent/computeIfAbsent as I am asking about the concept and not the use of API :) unless using this API contributes to HashMap vs ConcurrentHashMap subject.
Update 2016-12-30
This question was answered by a comment below by Holger "HashMap.get doesn’t modify the structure, but your invocation of put does. Since there is an invocation of get outside of the synchronized block, it can see an incomplete state of a put operation happening concurrently." Thanks!
This question is muddled on so many counts that its hard to answer.
If this code is only ever called from a single thread, then you're making it too complicated; you don't need any synchronization. But clearly that's not your intention.
So, multiple threads will call the fetch method, which delegates to HashMap.get() without any synchronization. HashMap is not thread-safe. Bam, end of story. Doesn't even matter if you're trying to simulate double-checked locking; the reality is that calling get() and put() on a map will manipulate the internal mutable data structures of the HashMap, without consistent synchronization on all code paths, and since you can be calling these concurrently from multiple threads, you're already dead.
(Also, you probably think that HashMap.get() is a pure read operation, but that's wrong too. What if the HashMap is actually a LinkedHashMap (which is a subclass of HashMap.) LinkedHashMap.get() will update the access order, which involves writing to internal data structures -- here, concurrently without synchronization. But even if get() is doing no writing, your code here is still broken.)
Rule of thumb: when you think you have a clever trick that lets you avoid synchronizing, you're almost certainly wrong.
I have a class which reads an xml file and populates them in a private static data-structure(say, HashMap). This initial population happens in a static block. Then I have method to get value of a given key, which intern refers that static HashMap. Cosider the case, when multiple threads tries to get value for a given key, will there be any performance hit; like, when one thread is reading that static object other threads has to wait.
public class Parser
{
private static HashMap resource = new HashMap();
static
{
parseResource();
}
private Parser()
{
}
private static parseResource()
{
//parses the resource and populates the resource object
}
public static Object getValue( String key)
{
//may be some check will be done here, but not any
//update/modification actions
return resource.get(key);
}
}
Firstly, it's worth being aware that this really has very little to do with static. There's no such thing as a "static object" - there are just objects, and there are fields and methods which may or may not be static. For example, there could be an instance field and a static field which both refer to the same object.
In terms of thread safety, you need to consider the safety of the operations you're interested in on a single object - it doesn't matter how the multiple threads have "reached" that object.
like, when one thread is reading that static object other threads has to wait.
No, it doesn't.
If you are just reading from the HashMap after constructing it in a way that prevented it from being visible to other threads until it had been finished, that's fine. (Having reread your comment, it looks like that's the case in getValue.)
If you need to perform any mutations on the map while other threads are reading from it, consider using ConcurrentHashMap or use synchronization.
From the docs for HashMap:
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.
You have no locking happening in your example code, so there's no way that multiple threads would need to wait.
Just adding to Jon Skeet's answer, for this kind of use you might want to consider Guava's ImmutableMap, which enforces immutability.
Just use the synchronized keyword and everything should work fine.
I have a Singleton class handling a kind of cache with different objects in a Hashmap.
(The format of a key is directly linked to the type of object stored in the map - hence the map is of )
Three different actions are possible on the map : add, get, remove.
I secured the access to the map by using a public entry point method (no intense access) :
public synchronized Object doAction(String actionType, String key, Object data){
Object myObj = null;
if (actionType.equalsIgnorecase("ADD"){
addDataToMyMap(key,data);
} else if (actionType.equalsIgnorecase("GET"){
myObj = getDataFromMyMap(key);
} else if (actionType.equalsIgnorecase("REM"){
removeDataFromMyMap(key);
}
return myObj;
}
Notes:
The map is private. Methods addDataToMyMap(), getDataFromMyMap() and removeDataFromMyMap() are private. Only the entry point method is public and nothing else except the static getInstance() of the class itself.
Do you confirm it is thread safe for concurrent access to the map since there is no other way to use map but through that method ?
If it is safge for a Map, I guess this principle could be applied to any other kind of shared ressource.
Many thanks in advance for your answers.
David
I would need to see your implementation of your methods, but it could be enough.
BUT i would recommend you to use a Map from the Collection API of java then you wouldnt need to synchronize your method unless your sharing some other instance.
read this: http://www.java-examples.com/get-synchronized-map-java-hashmap-example
Yes your class will be thread safe as long as the only entry point is doAction.
If your cache class has private HashMap and you have three methods and all are public synchronized and not static and if you don't have any other public instance variable then i think your cache is thread-safe.
Better to post your code.
This is entirely safe. As long as all the threads are accessing it using a common lock, which in this case is the Object, then it's thread-safe. (Other answers may be more performant but your implementation is safe.)
You can use Collections.synchronizedMap to synchronize access to the Map.
As is it is hard to determine if the code is thread safe. Important information missing from your example are:
Are the methods public
Are the methods synchronized
It the map only accessed through the methods
I would advice you to look into synchronization to get a grasp of the problems and how to tackle them. Exploring the ConcurrentHashMap class would give further information about your problem.
You should use ConcurrentHashMap. It offers better throughput than synchronized doAction and better thread safety than Collections.synchronizedMap().
This depends on your code. As someone else stated, you can use Collections.synchronizedMap. However, this only synchronizes the individual method calls on the map. So if:
map.get(key);
map.put(key,value);
Are executed at the same time in two different threads, one will block until the other exits. However, if your critical section is larger than the single call into the map:
SomeExpensiveObject value = map.get(key);
if (value == null) {
value = new SomeExpensiveObject();
map.put(key,value);
}
Now let's assume the key is not present. The first thread executes, and gets a null value back. The scheduler yields that thread, and runs thread 2, which also gets back a null value.
It constructs the new object and puts it in the map. Then thread 1 resumes and does the same, since it still has a null value.
This is where you'd want a larger synchronization block around your critical section
SomeExpensiveObject value = null;
synchronized (map) {
value = map.get(key);
if (value == null) {
value = new SomeExpensiveObject();
map.put(key,value);
}
}
I'm writing an analogue of DatabaseConfiguration class which reads configuration from database and I need some advice regards synchronization.
For example,
public class MyDBConfiguration{
private Connection cn;
private String table_name;
private Map<String, String> key_values = new HashMap<String,String>();
public MyDBConfiguration (Connection cn, String table_name) {
this.cn = cn;
this.table_name = table_name;
reloadConfig();
}
public String getProperty(String key){
return this.key_values.get(key);
}
public void reloadConfig() {
Map<String, String> tmp_map = new HashMap<String,String> ();
// read data from database
synchronized(this.key_values)
{
this.key_values = tmp_map;
}
}
}
So I have a couple questions.
1. Assuming properties are read only , do I have use synchronize in getProperty ?
2. Does it make sense to do this.key_values = Collections.synchronizedMap(tmp_map) in reloadConfig?
Thank you.
If multiple threads are going to share an instance, you must use some kind of synchronization.
Synchronization is needed mainly for two reasons:
It can guarantee that some operations are atomic, so the system will keep consistent
It guarantees that every threads sees the same values in the memory
First of all, since you made reloadConfig() public, your object does not really look immutable. If the object is really immutable, that is, if after initialization of its values they cannot change (which is a desired property to have in objects that are shared).
For the above reason, you must synchronize all the access to the map: suppose a thread is trying to read from it while another thread is calling reloadConfig(). Bad things will happen.
If this is really the case (mutable settings), you must synchronize in both reads and writes (for obvious reasons). Threads must synchronize on a single object (otherwise there's no synchronization). The only way to guarantee that all the threads will synchronize on the same object is to synchronize on the object itself or in a properly published, shared, lock, like this:
// synchronizes on the in instance itself:
class MyDBConfig1 {
// ...
public synchronized String getProperty(...) { ... }
public synchronized reloadConfig() { ... }
}
// synchronizes on a properly published, shared lock:
class MyDBConfig2 {
private final Object lock = new Object();
public String getProperty(...) { synchronized(lock) { ... } }
public reloadConfig() { synchronized(lock) { ... } }
}
The properly publication here is guaranteed by the final keyword. It is subtle: it guarantees that the value of this field is visible to every thread after initialization (without it, a thread might see that lock == null, and bad things will happen).
You could improve the code above by using a (properly published) ReadWriteReentrantLock. It might improve concurrency a bit if that's a concern for you.
Supposing your intention was to make MyDBConfig immutable, you do not need to serialize access to the hash map (that is, you don't necessarily need to add the synchronized keyword). You might improve concurrency.
First of all, make reloadConfig() private (this will indicate that, for consumers of this object, it is indeed immutable: the only method they see is getProperty(...), which, by its name, should not modify the instance).
Then, you only need to guarantee that every thread will see the correct values in the hash map. To do so, you could use the same techniques presented above, or you could use a volatile field, like this:
class MyDBConfig {
private volatile boolean initialized = false;
public String getProperty(...) { if (initialized) { ... } else { throw ... } }
private void reloadConfig() { ...; initialized = true; }
public MyDBConfig(...) { ...; reloadConfig(); }
}
The volatile keyword is very subtle. Volatile writes and volatile reads have a happens-before relationship. A volatile write is said to happen-before a subsequent volatile read of the same (volatile) field. What this means is that all the memory locations that have been modified before (in program order) a volatile write are visible to every other thread after they have executed a subsequente volatile read of the same (volatile) field.
In the code above, you write true to the volatile field after all the values have been set. Then, the method reading values (getProperty(...)) begins by executing a volatile read of the same field. Then this method is guaranteed to see the correct values.
In the example above, if you don't publish the instance before the constructor finishes, it is guaranteed that the exception won't get thrown in the method getProperty(...) (because before the constructor finishes, you have written true to initialized).
Assuming that key_values will not be put to after reloadConfig you will need to synchronize access to both reads and writes of the map. You are violating this by only synchronizing on the assignment. You can solve this by removing the synchronized block and assigning the key_values as volatile.
Since the HashMap is effectively read only I wouldn't assign Collections.synchronizedMap rather Collections.unmodifiableMap (this wouldn't effect the Map itself, just prohibit from accidental puts from someone else possible using this class).
Note: Also, you should never synchronize a field that will change. The results are very unpredictable.
Edit: In regards to the other answers. It is highly suggested that all shared mutable data must be synchronized as the effects are non-deterministic. The key_values field is a shared mutable field and assignments to it must be synchronized.
Edit: And to clear up any confusion with Bruno Reis. The volatilefield would be legal if you still fill the tmp_map and after its finished being filled assign it to this.key_values it would look like:
private volatile Map<String, String> key_values = new HashMap<String,String>();
..rest of class
public void reloadConfig() {
Map<String, String> tmp_map = new HashMap<String,String> ();
// read data from database
this.key_values = tmp_map;
}
You still need the same style or else as Bruno Reis noted it would not be thread-safe.
I would say that if you guarantee that no code will structurally modify your map, then there is no need to synchronize it.
If multiple threads access a hash map concurrently, and at least one
of the threads modifies the map structurally, it must be synchronized
externally.
http://download.oracle.com/javase/6/docs/api/java/util/HashMap.html
The code you have shown provides only read access to the map. Client code cannot make a structural modification.
Since your reload method alters a temporary map and then changes key_values to point to the new map, again I'd say no synchronization is required. The worst that can happen is someone reads from old copy of the map.
I'm going to keep my head down and wait for the downvotes now ;)
EDIT
As suggested by Bruno, the fly in the ointment is inheritance. If you cannot guarantee that your class will not be sub-classed, then you should be more defensive.
EDIT
Just to refer back to the specific questions posed by the OP...
Assuming properties are read only , do I have use synchronize in getProperty ?
Does it make sense to do this.key_values = Collections.synchronizedMap(tmp_map) in reloadConfig?
... I am genuinely interested to know if my answers are wrong. So I won't give up and delete my answer for a while ;)
I recently saw a piece of code which used a ThreadLocal object and kept a ConcurrentHashMap within it.
Is there any logic/benefit in this, or is it redundant?
If the only reference to the concurrent hashmap resides in the ThreadLocal, the hashmap is obviously only referenced from a single thread. In such case I would say it is completely redundant.
However, it's not hard to imagine someone "sharing" the thread-locally stored hashmap with other threads:
ThreadLocal<ConcurrentHashMap<String, String>> tl = ...
// ...
final ConcurrentHashMap<String, String> props = tl.get();
EventQueue.invokeLater(new Runnable() {
public void run() {
props.add(key.getText(), val.getText());
}
});
Either he used ThreadLocal wrongly, or ConcurrentHashMap wrongly. The likelihood that the combination makes sense is close to 0.
In addition to what #aioobe said, consider the case of InheritableThreadLocal, in which the value of local is passed from a thread to each child thread that it creates.
And as #pst says, there is nothing to prevent the same value being used in different (non-inheritable) ThreadLocals.
In short, you have to do a thorough analysis of the thread locals, the way that they are initialized and the way that they are used before you can safely conclude that they don't need to be threadsafe.