Reputation: 3965
I was looking at the code of java concurrent collections and I see that they just wrap simple collections with locking some lock in the beginning of the operation and unlocking it in the end.
What about volatile
? If the back end collection is not volatile the changes could be missed by other threads, and so the thread-saving is somewhat broken. I know that synchronized
can solve this issue, but they use just locks without any further synchronization.
Is that a problem, or am I missing something?
Update:
After a slight discussion I want to rephrase the question a bit.
I want to use a java collections in a multi threaded environment. (For instance currently I'm talking about PriorityBlockingQueue
)
I want to be sure that the changes one thread makes to the collection (push/pop) are immediately visible to others.
It is good that java concurrent collections prevent me from diving into troubles to keep the inner state of the collection stable when number of threads updates it, but I want to be sure that the data itself is visible to all threads.
The question is: am I correct that java concurrent collections don't provide this feature out of the box? And if I do, what additional (minimalistic cost) techniques should I use in order to do provide the desired visibility?
Thanks.
Upvotes: 8
Views: 4899
Reputation: 611
Here is the point wise answers to your questions. 1. All Java collection data structures in concurrency package do not wrap corresponding non thread safe collection data structures. 2. There are ways to achieve thread safety without using locks or synchronization. Writing lock free data structures is more involved and normally you should avoid for general development. But if there is one available, you should use them instead of the corresponding lock version of the data structure. 3. Lock free data structure do not use locks, still provide all the safety and liveness property. 4. Sample API is ConcurrentSkipListMap, which is lock free concurrent probabilistic map ( probably the most complicated implementation in Java)
Upvotes: 0
Reputation: 9150
EDIT: since the original question was clarified, this answer is no longer relevant. The answer below is relevant for the case when using Collections.synchronized* methods for making non-threadsafe collections threadsafe.
If you synchronize a block of code that will also cause different threads to synchronize the (possibly changed) state.
[...]
Either solution requires the clkID
variable to be reconciled with main memory. Accessing the clkID
variable from synchronized method or block does not allow that code to execute concurrently, but it does guarantee that the clkID
variable in main memory is updated appropriately. Main memory is updated when the object lock is obtained before the protected code executes, and then when the lock is released after the protected code executes.
[...]
Source: Use Synchronized or Volatile when Accessing Shared Variables
Upvotes: 5
Reputation: 21306
From BlockingQueue
's Javadoc:
Memory consistency effects: As with other concurrent collections, actions in a thread prior to placing an object into a
BlockingQueue
happen-before actions subsequent to the access or removal of that element from theBlockingQueue
in another thread.
PriorityBlockingQueue
provides this behaviour by means of a ReentrantLock
which (being an implementation of Lock
):
...provide[s] the same memory synchronization semantics as provided by the built-in monitor lock, as described in the JLS...
Upvotes: 11
Reputation: 1230
yes, you are missing something. the ReentrantLock class provides the same guarantees as synchronized. And, ReentrantLock and synchronized both provide the same memory guarantees as volatile.
Upvotes: 8
Reputation: 88796
I was looking at the code of java concurrent collections and I see that they just wrap simple collections with locking some lock in the beginning of the operation and unlocking it in the end.
What source were you reading?
This is an over-generalization. It depends entirely on which collection you're looking at. For example, CopyOnWriteArrayList
does nothing of the sort, but creates an entirely new array every time you add or remove elements, which means any open Iterator
or ListIterator
will continue running with the old data; this effect is intentional.
What about volatile? If the back end collection is not volatile the changes could be missed by other threads, and so the thread-saving is somewhat broken. I know that synchronized can solve this issue, but they use just locks without any further synchronization.
Most of the concurrent collections exist to make sure Iterators continue to operate on the old version rather than the new version that has updated data; something that volatile
would not guarantee. This behavior also means that the Iterators will not be left in an inconsistent state, and thus preventing ConcurrentModificationException
from being thrown.
Upvotes: 6