0

There is no practical need for a constructor to be synchronized, because it would lock the object under construction, which is normally not made available to other threads until all constructors for the object have completed their work.

above is in https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.8.3

But I found LOCK used in ArrayBlockingQueue's Constructor. Why it is used ?

public ArrayBlockingQueue(int capacity, boolean fair,  Collection<? extends E> c) {
        this(capacity, fair);
        final ReentrantLock lock = this.lock;
        lock.lock(); // Lock only for visibility, not mutual exclusion
        try {
            int i = 0;
            try {
                for (E e : c) {
                    checkNotNull(e);
                    items[i++] = e;
                }
            } catch (ArrayIndexOutOfBoundsException ex) {
                throw new IllegalArgumentException();
            }
            count = i;
            putIndex = (i == capacity) ? 0 : i;
        } finally {
            lock.unlock();
        }
    }
tian chu
  • 3
  • 1

1 Answers1

2

The comment // Lock only for visibility, not mutual exclusion tells you about it. Depending on the CPU we can have a situation where the constructing thread "leaves" our constructor but the fields are not yet initialized (so in our example thread leaves ArrayBlockingQueue constructor but our count, putIndex, items fields are not yet initialized and some other thread started using offer/add methods). The same lock strategy is used in LinkedBlockingQueue. Also, JVM have capabilities to reorder our bytecode instructions inside our method/constructor. And for last there may be a situation that a thread can obtain a reference before another thread finishes constructing the object.

Here you can read more about it:

Constructor synchronization in Java

And also, there are many blog posts about Memory Visibility.