Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Concurrency in Practice - Sample 14.12

// Not really how java.util.concurrent.Semaphore is implemented
@ThreadSafe
public class SemaphoreOnLock {
    private final Lock lock = new ReentrantLock();
    // CONDITION PREDICATE: permitsAvailable (permits > 0)
    private final Condition permitsAvailable = lock.newCondition();
    @GuardedBy("lock") private int permits;

    SemaphoreOnLock(int initialPermits) {
        lock.lock();
        try {
            permits = initialPermits;
        } finally {
            lock.unlock();
        }
    }

/* other code omitted.... */

I have a question about the sample above which is extracted from Java Concurrency in Practice Listing 14.12 Counting Semaphore Implemented Using Lock.

I am wondering why we need to acquire the lock in the constructor (as shown lock.lock() is invoked). As far as i know, constructor is atomic (except the reference escaped) as no other thread can get the reference, hence, the half-constructed-object is not visible to other threads. Therefore, we do not need the synchronized modifier for constructors. Besides, we do not need to worry about the memory visibility as well, as long as the object is safely published.

So, why do we need to get the ReentrantLock object inside the constructor?

like image 946
ben ben Avatar asked May 10 '12 06:05

ben ben


1 Answers

the half-constructed-object is not visible to other threads

It is not true. The object is visible to other threads at the time of construction if it has any non final/volatile fields. Therefore, other threads might see a default value for permits i.e 0 which might not be consistent with the current thread.

The Java memory model offers a special guarantee of initialization safety for immutable objects (object with only final fields). An object reference visible to another thread does not necessarily mean that the state of that object is visible to the consuming thread - JCP $3.5.2

From Listing 3.15 of Java Concurrency in Practice:

While it may seem that field values set in a constructor are the first values written to those fields and therefore that there are no "older" values to see as stale values, the Object constructor first writes the default values to all fields before subclass constructors run. It is therefore possible to see the default value for a field as a stale value.

like image 88
Prince John Wesley Avatar answered Oct 13 '22 19:10

Prince John Wesley