synchronized vs lock vs synchronized map - java

I need to synchrozize my accesses to the hashmap.
Here are my options
I know I can use Synchronize keyword. this is one option. Can I use the map itself ?
currently I have a get method that if the object does not exists creates it and puts it in the map. I can synchronize the method.
I can use a syncronize block
I can use
Map m = Collections.synchronizedMap(new HashMap(...));
in my code.
I tend to do 4 cause it sounds the easiest. Any suggestions?

I would suggest that you don't make methods synchronized, and that you don't lock on the map itself. I generally prefer to use a separate locking object which is only used for locking and only known about in the class which owns the map.
You could potentially use synchronizedMap, but it depends what you want to do with it. If you only ever get and put values, then that's fine. If you ever need to iterate over the map, you need to block other threads from modifying the map while you're iterating.
Another option is to use a ConcurrentHashMap. See the docs for the semantics. This is probably the simplest approach if it behaves the way you need it to.

You could use ConcurrentHashMap.putIfAbsent() which may do what you want without synchronisation.

Related

Is collection synchronizing (via Collections.synchronizedX) necessary when access methods are synchronized?

There is a lot of topics when synchronization in Java appears. In many of them is recommended to using invokation of Collections.synchronized{Collecation, List, Map, Set, SortedMap, SortedSet} instead of Collection, List, etc. in case of multithreading work to thread-safe access.
Lets imagine situation when some threads exist and all of them need to access collection via methods that have synchronized block in their bodies.
So then, is it necessary to use:
Collection collection = Collections.synchronizedCollection(new ArrayList<T>());
or only
Collection collection = new ArrayList<String>();
need to?
Maybe you can show me an example when second attempt instead of first will cause evidently incorrect behaviour?
To the contrary, Collections.synchronizedCollection() is generally not sufficient because many operations (like iterating, check then add, etc.) need additional, explicit synchronization.
If every access to the collection is already done through properly synchronized methods, then wrapping the collection again into a syncronized proxy is useless.
No, if your access methods are synchronized there is no need to also use a synchronized collection.
Collection collection = new ArrayList<String>();
will do just fine in that scenario.
If you have already arranged for proper synchronization of your code, you definitely do not need another layer of synchronization on the lower level of granularity.
Just make sure when you say
all of them need to access collection via methods that have synchronized block in their bodies.
that all these blocks use the same lock. It is not enough to just involve some synchronized block.

EnumMap with concurrent put/get

I am considering using EnumMap in a concurrent environment. However, the environment is atypical, here's why:
EnumMap is always full: there are no unmapped keys when the map is exposed to the concurrent environment
Only put() and get() operations will be used (no iterating over, no remove(), etc.)
It is completely acceptable if a call to get() does not reflect a call to put() immediately or orderly.
From what I could gather, including relevant method source code, this seems to be a safe scenario (unlike if iterations were allowed). Is there anything I might have overlooked?
In general, using non-thread-safe classes across threads is fraught with many problems. In your particular case, assuming safe publication after all keys have had values assigned (such that map.size() == TheEnum.values().length), the only problem I can see from a quickish glance of EnumMap's code in Java 1.6 is that a put may not ever get reflected in another thread. But that's only true because of the internals of EnumMap's implementation, which could change in the future. In other words, future changes could break the use case in more dangerous, subtle ways.
It's possible to write correct code that still contains data races -- but it's tricky. Why not just wrap the instance in a Collections.synchronizedMap?
Straight from the JavaDoc:
Like most collection implementations EnumMap is not synchronized. If multiple threads access an enum map concurrently, and at least one of the threads modifies the map, it should be synchronized externally. This is typically accomplished by synchronizing on some object that naturally encapsulates the enum map. If no such object exists, the map should be "wrapped" using the Collections.synchronizedMap(java.util.Map<K, V>) method. This is best done at creation time, to prevent accidental unsynchronized access:
Map<EnumKey, V> m = Collections.synchronizedMap(new EnumMap<EnumKey, V>(...));
The problem you have is that threads may not ever see the change made by another thread or they may see partially made changes. It's the same reason double-check-locking was broken before java 5 introduced volatile.
It might work if you made the EnumMap reference volatile but I'm not 100% sure even then, you might need the internal references inside the EnumMap to be volatile and obviously you can't do that without doing your own version of EnumMap.

mutual exclusion using Hashtable of java

hi mate i have a global Hashtable in my class, and two thread A and B that work with her.
A reads from HashTable and B write in Hashtable.. is there a problem of mutual exclusion ? i need to syncrhonize it or Hashtable class is safe ?
Hashtable is a thread-safe implementation of the Map interface.
In regular put and get operations you will be safe. However, when you will iterate on it in one thread and modify its contents from another thread, you will have ConcurrentModificationException issues. So, when iterating, make sure you iterate on a copy of the original Hashtable.
You should use ConcurrentHashMap instead, which is a much better/faster implementation of java.util.Map interface.
It's useful to use a synchronized HashMap offered by java collections. This class is a simple wrapper and encapsulates the hashmap :
Collections.synchronizedMap(new HashMap());
Further example example is in the java docs :
http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Collections.html synchronizedMap
HashTable gaurantees that any operation executed on it is atomic. but If you are executing multiple operations you should synchronize them. In below example even if contains and put are atomic but the code has a check and act raise condition so you need additional synchronization for this.
if(!hashtable.contains(Object))
{
hashtable.put(key, value);
}
Also check Collections.synchronizedMap() or ConcurrentHashMap rather than HashTable
Everyone has said what can be said but this is just to complement with regards to what you call mutual exclusion. You are asking if there won't be such a problem. A thread-safe program must ensure that that if threadA is using say a block of code block1 no other thread will access it until the thread is done. So, if I understand well what you mean by mutual exclusion, yes threads accessing the same synchronized (thread-safe) shared resource are mutually exclusive because they both can't access it at the same time.
Java practically does much of the hard for you if you choose one of the proposed safe Map implementation. Now if your Hashtable ( or whatever else thread-safe mao you prefer ) is a shared resource, the only thing you need to take care of is the happens-before relation. It will be important if one thread is reading data and the other writing data.
More can be found at java concurrency tutorial and java concurrent package docs

Is java.util.Hashtable thread safe?

It's been a while since I've used hashtable for anything significant, but I seem to recall the get() and put() methods being synchronized.
The JavaDocs don't reflect this. They simply say that the class Hashtable is synchronized. What can I assume? If several threads access the hashtable at the same time (assuming they are not modifying the same entry), the operations will succeed, right? I guess what I'm asking is "Is java.util.Hashtable thread safe?"
Please Guide me to get out of this issue...
It is threadsafe because the get, put, contains methods etc are synchronized. Furthermore, Several threads will not be able to access the hashtable at the same time, regardless of which entries they are modifying.
edit - amended to include the provisio that synchronization makes the hashtable internally threadsafe in that it is modified atomically; it doesn't guard against race conditions in outside code caused by concurrent access to the hashtable by multiple threads.
For general usage it is thread safe.
But you have to understand that it doesent make your application logic around it thread-safe. For e.g. consider implementing to put a value in a map, if its not there already.
This idiom is called putIfAbsent. Its difficult to implement this in a thread-safe manner using HashTable alone. Similarly for the idiom replace(k,V,V).
Hence for certain idioms like putIfAbsent and and replace(K,V,V), I would recommend using ConcurrentHashMap
Hashtable is deprecated. Forget it. If you want to use synchronized collections, use Collections.syncrhonize*() wrapper for that purpose. But these ones are not recommended. In Java 5, 6 new concurrent algorithms have been implemented. Copy-on-write, CAS, lock-free algorithms.
For Map interface there are two concurrent implementations. ConcurrentHashMap (concurrent hash map) and ConcurrentSkipListMap - concurrent sorted map implementaion.
The first one is optimized for reading, so retrievals do not block even while the table is being updated. Writes are also work much faster comparing with synchronized wrappers cause a ConcurrentHashMap consists of not one but a set of tables, called segments. It can be managed by the last argument in the constructor:
public ConcurrentHashMap(int initialCapacity,
float loadFactor,
int concurrencyLevel);
ConcurrentHashMap is indispensable in highly concurrent contexts, where it performs far better than any available alternative.
No. It is 'threadsafe' only to the extent that its methods are synchronized. However it is not threadsafe in general, and it can't be, because classes that export internal state such as Iterators or Enumerations require the use of the internal state to be synchronized as well. That's why the new Collections classes are not synchronized, as the Java designers recognized that thread-safety is up to the user of the class, not the class itself.
I'm asking is "Is java.util.Hashtable thread safe?".
Yes Hashtable is thread safe, If a thread safe is not needed in your application then go through HashMap, In case, If a thread-safe implementation is desired,then it is recommended to use ConcurrentHashMap in place of Hashtable.
Note, that a lot of the answers state that Hashtable is synchronised. but this will give you a very little. The synchronization is on the accessor / mutator methods will stop two threads adding or removing from the map concurrently, but in the real world you will often need additional synchronisation.
Even iterating over a Hashtable's entries is not thread safe unless you also guard the Map from being modified through additional synchronization.
If you look into Hashtable code, you will see that methods are synchronized such as:
public synchronized V get(Object key)
public synchronized V put(K key, V value)
public synchronized boolean containsKey(Object key)
You can keep pressing on control key (command for mac) and then click on any method name in the eclipse to go to the java source code.
Unlike the new collection implementations, Hashtable is synchronized. *If a thread-safe implementation is not needed, it is recommended to use HashMap* in place of Hashtable. If a thread-safe highly-concurrent implementation is desired, then it is recommended to use ConcurrentHashMap in place of Hashtable.
http://download.oracle.com/javase/7/docs/api/java/util/Hashtable.html
Yes, Hashtable thread safe, so only one thread can access a hashtable at any time
HashMap, on the other side, is not thread safe (and thus 'faster').

How to clone a synchronized Collection?

Imagine a synchronized Collection:
Set s = Collections.synchronizedSet(new HashSet())
What's the best approach to clone this Collection?
It's prefered that the cloning doesn't need any synchronization on the original Collection but required that iterating over the cloned Collection does not need any synchronization on the original Collection.
Use a copy-constructor inside a synchronized block:
synchronized (s) {
Set newSet = new HashSet(s); //preferably use generics
}
If you need the copy to be synchronized as well, then use Collections.synchronizedSet(..) again.
As per Peter's comment - you'll need to do this in a synchronized block on the original set. The documentation of synchronizedSet is explicit about this:
It is imperative that the user manually synchronize on the returned set when iterating over it
When using synchronized sets, do understand that you will incur synchronization overhead accessing every element in the set. The Collections.synchronizedSet() merely wraps your set with a shell that forces every method to be synchronized. Probably not what you really intended. A ConcurrentSkipListSet will give you better performance in a multithreaded environment where multiple threads will be writing to the set.
The ConcurrentSkipListSet will allow you to perform the following:
Set newSet = s.clone();//preferably use generics
It's not uncommon to use a clone of a set for snapshot processing. If that's what you are after, you might add a little code to handle the case where the item is already processed. The overhead involved with the occasional object included in more than one copy set is usually less than the consistent overhead of using Collections.concurrentSet().
EDIT: I just noticed that ConcurrentSkipListSet is Cloneable and provides a threadsafe clone() method. I changed my answer because I really believe this is the best option--instead of losing scalability and performance to Collections.concurrentSet().
You can avoid synchronizing the set by doing the following which avoids exposing an Iterator on the original set.
Set newSet = new HashSet(Arrays.asList(s.toArray()));
EDIT From Collections.SynchronizedCollection
public Object[] toArray() {
synchronized(mutex) {return c.toArray();}
}
As you can see, the lock is held for the entire time the operation is performed. As such a safe copy of the data is taken. It doesn't matter if an Iterator is used internally. The array returned can be used in a thread safe manner as only the local thread has a reference to it.
NOTE: If you want to avoid these issues I suggest you use a Set from the concurrency library added in Java 5.0 in 2004. I also suggest you use generics as this can make your collections more type safe.

Categories