为什么ArrayBlockingQueue构造函数需要在JDK 8中锁定

时间:2018-08-10 07:27:32

标签: java synchronization

  

实际上不需要同步构造函数,因为它会锁定正在构造的对象,通常在该对象的所有构造函数完成工作之前,其他线程无法使用它。

上方是https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.8.3

但是我发现LOCK在ArrayBlockingQueue的构造函数中使用。为什么使用它?

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();
        }
    }

1 个答案:

答案 0 :(得分:2)

评论// Lock only for visibility, not mutual exclusion告诉您。根据CPU的不同,我们可能会遇到以下情况:构造线程“离开”了构造函数,但尚未初始化字段(因此,在示例中,线程离开了ArrayBlockingQueue构造函数,而我们的count,{{1} },putIndex字段尚未初始化,并且其他一些线程已使用items / offer方法启动)。 add中使用了相同的锁定策略。而且,JVM具有在我们的方法/构造函数中对字节码指令重新排序的功能。最后,可能存在这样的情况,一个线程可以在另一个线程完成构造对象之前获得引用。

在这里您可以阅读有关它的更多信息:

Constructor synchronization in Java

而且,还有许多有关“内存可见性”的博客文章。