0

I am developing a pool mechanism. Objects in the pool will be used by different threads. Thus I need to guarantee that there will be a happens-before relation when accessing non-final attributes of these objects.

As a given object will be accessed by only one thread at a time, I do not need to guarantee any atomicity. What is more optimized when only happens-before needs to be achieved? To use a synchronized block on a final attribute each time I read or modify one of the non-final attribute? Or to use concurrent classes, such as a ConcurrentMap?

(I am not asking this question for attributes of the pool itself, that obviously needs to provide atomicity; I am only asking this question for the attributes of objects obtained from the pool)

FBB
  • 1,414
  • 2
  • 17
  • 29

4 Answers4

3

To use a synchronized block on a final attribute each time I read or modify one of the non-final attribute? Or to use concurrent classes, such as a ConcurrentMap?

Synchronization is built around an internal entity known as the intrinsic lock or monitor lock. Every object has an intrinsic lock associated with it. By convention, a thread that needs exclusive and consistent access to an object's fields has to acquire the object's intrinsic lock before accessing them, and then release the intrinsic lock when it's done with them.

An implementation of ConcurrentMap i.e., ConcurrentHashMap uses reentrant lock which is mutual exclusive lock, Lock is acquired by lock() method and held by Thread until a call to unlock() method. Though, ReentrantLock provides same visibility and orderings guaranteed as implicit lock, acquired by synchronized keyword, it provides more functionality and differ in certain aspect:

  1. ReentrantLock can be made fair by specifying fairness property to provides lock to longest waiting thread, in case of contention.
  2. provides convenient tryLock() method to acquires lock, only if its available or not held by any other thread, reducing blocking of thread waiting for lock. tryLock() with timeout can be used to timeout if lock is not available in certain time period.
  3. In case of synchronized keyword, a thread can be blocked waiting for lock, for an indefinite period of time and there was no way to control that. ReentrantLock provides a method called lockInterruptibly(), which can be used to interrupt thread when it is waiting for lock.

An example of use reentrant lock can be shown from ConcurrentHashMap's inner replace(K key, V oldValue, V newValue) function implementaion:

boolean replace(K key, int hash, V oldValue, V newValue) { 
               // called by replace(K key, V oldValue, V newValue)
        lock(); // acquire the lock
        try {
            HashEntry<K,V> e = getFirst(hash);
            while (e != null && (e.hash != hash || !key.equals(e.key)))
                e = e.next;

            boolean replaced = false;
            if (e != null && oldValue.equals(e.value)) {
                replaced = true;
                e.value = newValue;
            }
            return replaced;
        } finally {
            unlock(); // unlock 
        }
    }

There are other functions like put(), writeObject(java.io.ObjectOutputStream), etc. are also implemented using reentrant synchronization using the ReentrantLock, without which, synchronized code would have to take many additional precautions to avoid having a thread cause itself to block. That is why I think for your case ConcurentMap is preferable.

Reference:

  1. Intrinsic Locks and Synchronization
  2. ReentrantLock Class
  3. Difference between synchronized vs ReentrantLock
  4. ConcurrentHashMap
Sage
  • 15,290
  • 3
  • 33
  • 38
  • Actually, it seems that the synchronized keyword also provides reentrant synchronization: http://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html. But thank you for the detailed answer, you provide other valid points. – FBB Oct 14 '13 at 11:38
  • yes it can, but we need to bring lots of control to it which `ReentrantLock class` already providing. I just wanted to point out the advantages `ReentrantLock` class is providing for us. I have read my post once again carefully, it seems i should have mentioned `ReentrantLock class` at the last para right after **reentrant synchronization**. updated the answer. Thanks :) – Sage Oct 14 '13 at 11:57
  • Of note, see also @ewernli answer, who gives an answer specific to my use case of a pool. – FBB Oct 15 '13 at 10:18
2

As a given object will be accessed by only one thread at a time, I do not need to guarantee any atomicity.

If I get it right, what you mean is that your objects will be shared accross threads, but there is actually no concurrency going on (objects are never accessed concurrently by multiple threads). You're wondering what synchronization is needed.

I've been wondering the same, and my conclusion was the following: if object Y synchronizes accesses to object X, object X doesn't need to be synchronized itself. In the case of a pool, you probably obtain and release objects using methods that are synchronized, so they protect the object in the pool.

Let's consider object O in the pool. The pool has two methods Object acquire() and release(Object o) that are synchronized. To pass object O from thread T1 to T2, T1 must first release O, and T2 must then acquire O. There is already a happen-before relationship between T1's release and T2's acquire, so the object O doesn't need to be itself synchronized.

Community
  • 1
  • 1
ewernli
  • 38,045
  • 5
  • 92
  • 123
  • Wow, you are actually right, I did not realize that. But, in the link to your question, someone warns about future code change, and I tend to agree with him. I upvote your answer but I do not accept it, because @Sage replies to the actual question, not to the one I was thinking about without being aware of it, sorry :p – FBB Oct 14 '13 at 11:41
  • @Djebel You shouldn't synchronize something if you don't need to. If your pool is correctly implemented, objects in the pool don't need to be synchronized (and won't need in the future). There's no "more optimized" approach to synchronization than not doing it :) – ewernli Oct 14 '13 at 14:26
  • Yes, @assylias's comment gave me doubts about my use case, but you are right, as long as there is only one thread that can access object O at a time, and the exchange between threads is synchronized, happens-before is guaranteed. – FBB Oct 15 '13 at 10:16
0

If the field you need the happens-before relationship on is a primitive, and you are using Java 5 or later, then you can use the volatile keyword which in Java 5+ ensures happens-before reading.

If it's an object, then you need to use some kind of synchronization either using the synchronized key word or a class from the java.util.concurrent package which often has better performance than naive synchronization. For example, ConcurrentHashMap usually has better performance than Collections.synchronizedMap(Map) because it uses separate locks for each bin so there is less lock contention.

dkatzel
  • 31,188
  • 3
  • 63
  • 67
  • I agree that there is less lock contention for classes from `java.util.concurrent`, but as their methods need to ensure atomicity, isn't it less efficient at the end? – FBB Oct 13 '13 at 00:24
  • 1
    CHM won't guarantee that changes made to the objects will be visible (there is no happens before between two calls to get for example). – assylias Oct 13 '13 at 01:01
  • @assylias: yes it will, see http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ConcurrentMap.html – FBB Oct 14 '13 at 11:23
  • 1
    @Djebel the link you provide says otherwise. If you `modify(o); put(key, o)` then a `o = get(key)` will point to the latest version of `o` and see the changes. But if you `o = get(key); modify(o);` without a put, a subsequent `o2 = get(key);` is not guaranteed to see the changes. – assylias Oct 14 '13 at 12:36
-1

well if you need to guarantee a Happens-Before, i think you can create a Synchronized block, holding the Object you want to lock, then in this block, do what you want it to be done before using this object, then invoke your stuff from the Object, then release

for instance

public void doSomething(){
    synchronized(myObject){
        doAnotherThing();
        myObject.doStuff();
    }
}

i didnt try the ConcurrentMap before by the way ... and by the way, please clarify your example because i think i didnt get you right !!

Ahmed Adel Ismail
  • 2,168
  • 16
  • 23
  • 1
    I did not downvote you, but I guess it is because you do not answer the question. You explain how to use the `synchronized` keyword, while I was asking for a comparison of the advantages/inconvenients of using this keyword vs. using classes from `java.util.concurrent` package. – FBB Oct 14 '13 at 11:44