Is there any benefit in puting a ThreadSafe object on a ThreadLocal? - java

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.

Related

Modify outer object from inside a thread

public void fooAndBar() {
HashMap<Foo, Bar> fooBarMap = new HashMap<>();
CompletionService completionService = new ExecutorCompletionService(exec);
for(int i=0; i<10; i++) {
completionService.submit(new Callable() {
#Override
public Void call() throws Exception {
fooBarMap.put(new Foo(i), new Bar(i));
return null;
}
});
}
}
Is it safe to modify the HashMap inside the Callable?
Should the hashmap be final (or maybe volatile) and if so, why?
Should I use a structure other than HashMap, something like ConcurrentHashMap or SynchronizedMap and why?
I'm trying to grasp java concepts so please bear with me
Is it safe to modify the HashMap inside the Callable?
No. If you are using a threadpool I assume you are planning to have more of those callables running in parallel. Any time an object with mutable state is accessed from more than one thread, that's thread-unsafe. If you write to a thread-unsafe hashmap from two threads simultaneously, its internal structure will be corrupted. If you read from a thread-unsafe hashmap while another thread is writing to it simultaneously, your reading thread will read garbage. This is a very well known and extensively studied situation known as a Race Condition, a description of which would be totally beyond the scope of this answer. For more information, read about Race Condition on Wikipedia or on another question answered back in 2008: Stackoverflow - What is a Race Condition.
Should the hashmap be final (or maybe volatile) and if so, why?
For your purposes it does not need to be final, but it is always a good practice to make final anything that can be made final.
It does not need to be volatile because:
if you were to make it volatile, you would be making the reference to it volatile, but the reference never changes, it is its contents that change, and volatile has nothing to do with those.
the threadpool makes sure that call() will be executed after fooBarMap = new HashMap<>(). (If you are wondering why such a thing could ever be a concern, google for "memory boundary".)
Should I use a structure other than HashMap, something like ConcurrentHashMap or SynchronizedMap and why?
Definitely. Because, as I wrote earlier, any time an object with mutable state is accessed from more than one thread, that's thread-unsafe. And ConcurrentHashMap, SynchronizedMap, synchronize, etc. exist precisely for taking care of thread-unsafe situations.
Hashmap should not be final, as you are modifying it multiple times(from within a for loop).
If you make it final, you may get an error.

Java visibility: final static non-threadsafe collection changes after construction

I found the following code snippet in luaj and I started to doubt that if there is a possibility that changes made to the Map after it has been constructed might not be visible to other threads since there is no synchronization in place.
I know that since the Map is declared final, its initialized values after construction is visible to other threads, but what about changes that happen after that.
Some might also realize that this class is so not thread-safe that calling coerce in a multi-threaded environment might even cause infinite loop in the HashMap, but my question is not about that.
public class CoerceJavaToLua {
static final Map COERCIONS = new HashMap(); // this map is visible to all threads after construction, since its final
public static LuaValue coerce(Object paramObject) {
...;
if (localCoercion == null) {
localCoercion = ...;
COERCIONS.put(localClass, localCoercion); // visible?
}
return ...;
}
...
}
You're correct that changes to the Map may not be visible to other threads. Every method that accesses COERCIONS (both reading and writing) should be synchronized on the same object. Alternatively, if you never need sequences of accesses to be atomic, you could use a synchronized collection.
(BTW, why are you using raw types?)
This code is actually bad and may cause many problems (probably not infinite loop, that's more common with TreeMap, with HashMap it's more likely to get the silent data loss due to overwrite or probably some random exception). And you're right, it's not guaranteed that the changes made in one thread will be visible by another one.
Here the problem may look not very big as this Map is used for caching purposes, thus silent overwrites or visibility lag doesn't lead to real problems (just two distinct instances of coersion will be used for the same class, which is probably ok in this case). However it's still possible that such code will break your program. If you like, you can submit a patch to LuaJ team.
Two options:
// Synchronized (since Java 1.2)
static final Map COERCIONS = Collections.synchronizedMap(new HashMap());
// Concurrent (since Java 5)
static final Map COERCIONS = new ConcurrentHashMap();
They each have their pros and cons.
ConcurrentHashMap pro is no locking. Con is that operations are not atomic, e.g. an Iterator in one thread and a call to putAll in another will allow iterator to see some of the values added.

Is this code multi-thread safe?

private static Map<Integer, String> map = null;
public static String getString(int parameter){
if(map == null){
map = new HashMap<Integer, String>();
//map gets filled here...
}
return map.get(parameter);
}
Is that code unsafe as multithreading goes?
As mentioned, it's definitely not safe. If the contents of the map are not based on the parameter in getString(), then you would be better served by initializing the map as a static initializer as follows:
private static final Map<Integer, String> MAP = new HashMap<Integer,String>();
static {
// Populate map here
}
The above code gets called once, when the class is loaded. It's completely thread safe (although future modification to the map are not).
Are you trying to lazy load it for performance reasons? If so, this is much safer:
private static Map<Integer, String> map = null;
public synchronized static String getString(int parameter){
if(map == null){
map = new HashMap<Integer, String>();
//map gets filled here...
}
return map.get(parameter);
}
Using the synchronized keyword will make sure that only a single thread can execute the method at any one time, and that changes to the map reference are always propagated.
If you're asking this question, I recommend reading "Java Concurrency in Practice".
Race condition? Possibly.
If map is null, and two threads check if (map == null) at the same time, each would allocate a separate map. This may or may not be a problem, depending mainly on whether map is invariant. Even if the map is invariant, the cost of populating the map may also become an issue.
Memory leak? No.
The garbage collector will do its job correctly regardless of the race condition.
You do run the risk of initializing map twice in a multi-threaded scenario.
In a managed language, the garbage collector will eventually dispose of the no-longer-referenced instance. In an unmanaged language, you will never free the memory allocated for the overwritten map.
Either way, initialization should be properly protected so that multiple threads do not run initialization code at the same time.
One reason: The first thread could be in the middle of initializing the HashMap, while a second thread comes a long, sees that map is not null, and merrily tries to use the partially-initialized data structure.
It is unsafe in multithreading case due to race condition.
But do you really need the lazy initialization for the map? If the map is going to be used anyway, seems you could just do eager initialization for it..
The above code isn't thread-safe, as others have mentioned, your map can be initialized twice. You may be tempted to try and fix the above code by adding some synchronization, this is known as "double checked locking", Here is an article that describes the problems with this approach, as well as some potential fixes.
The simplest solution is to make the field a static field in a separate class:
class HelperSingleton {
static Helper singleton = new Helper();
}
it can also be fixed using the volatile keyword, as described in Bill Pugh's article.
No, this code is not safe for use by multiple threads.
There is a race condition in the initialization of the map. For example, multiple threads could initialize the map simultaneously and clobber each others' writes.
There are no memory barriers to ensure that modifications made by a thread are visible to other threads. For example, each thread could use its own copy of the map because they never "see" the values written by another thread.
There is no atomicity to ensure that invariants are preserved as the map is accessed concurrently. For example, a thread that's performing a get() operation could get into an infinite loop because another thread rehashed the buckets during a simultaneous put() operation.
If you are using Java 6, use ConcurrentHashMap
ConcurrentHashMap JavaDoc

Synchronized block and variable scope

Can anyone explain to me how the parameter map will be affected in the following code if two threads access it at the same time. Is the map exposed to thread safety issues because it is not inside the synchronized block?
public void fun(String type, String name, Map<String, Object> parameters) {
parameters.put(Constants.PARM_TYPE, type);
parameters.put(Constants.PARM_NAME, name);
try {
synchronized (launcher) {
launcher.launch(type, bool, parameters);
}
} catch (Exception e) {
logger.error("AHHHHH, the world has ended!",e);
}
}
I have looked at the following but I'm still questioning it: Synchronized and the scope of visibility
If your parameters instances are separate (as you mentioned in your last comment), then there is no problem with this code.
The method parameters - besides Map parameters - are just 2 Strings, so there are no synchronisation issues regarding them.
To put the synchronized block onto method level or on launcher: They're different objects. If you put on method, it will synchronize on this, otherwise on launcher. Since you want to protect the 'launcher', you have to "build the fence" as close as you can - so synchronizing on launcher is OK.
There is another technique which is using a Object lockObject = new Object(), and does the synchronization on that object, but for this purpuse I think it's overkill, but you can do that.
Imagine if you had a shared Map.
private Map<String, Object> map = new HashMap<String,Object>();
that is being updated by many threads as displayed in your example.
new Thread(new Runnable(){
public void run(){
fun("a","b", map);
}
}).start();
new Thread(new Runnable(){
public void run(){
fun("a","b", map);
}
}).start();
Each thread may update the map at the same time which could lead to A Beautiful Race Condition
If multiple threads have a handle to the same parameters instance and they call this method (which modifies the map) with a non-thread-safe map implementation, all kinds of bad things can/will happen (e.g. map corruption which may/may not manifest itself as exceptions like NullPointerException).
Assuming multiple threads are accessing the method fun(), the way map works is if you insert the same key multiple times then the value of that key would be overridden each time. But this might not be the only problem. There could be race conditions and corruption issues too. If you want an implicitly thread safe data structure, I assume a HashTable will get your job done.
if more than one thread executes that code concurrently passing the same object as the parameter map then you will have a race condition.
This will definitely cause thread safety issues unless you:
use the right Map implementation, based on your requirements and the Map implementation concurrent behavior (ConcurrentHashMap for instance, but this depends a lot on the actual requirements for your app)
or write thread safe code yourself (probably using synchronization primitives like 'synchronized').
IMPORTANT: Please notice that just moving the lines of code that modify the map into the synchronized block won't necessarily remove the race condition as you'll have to consider which other threads in your app may try to modify the map and which object they will use to synchronize their access to it. The code in the function is using a reference to 'launcher' to synchronize. Any other thread modifying the map without synchronization or with synchronization over an object different than 'launcher' will cause a race condition

Is this usage of synchronizedMap thread safe?

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>());

Categories

Resources