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.
以上内容在 https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.8.3
但是我发现ArrayBlockingQueue的构造函数中使用了LOCK。为什么使用它?
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();
}
}
最佳答案
注释 //Lock only forvisibility, notmutualclusion
告诉您这一点。根据 CPU 的不同,我们可能会遇到这样的情况:构造线程“离开”我们的构造函数,但字段尚未初始化(因此在我们的示例中,线程离开 ArrayBlockingQueue
构造函数,但我们的 count
、putIndex
、items
字段尚未初始化,并且其他一些线程使用 offer
/add
方法启动)。 LinkedBlockingQueue
中使用了相同的锁定策略。此外,JVM 有能力在我们的方法/构造函数中重新排序字节码指令。最后,可能存在这样的情况:一个线程可以在另一个线程完成构造对象之前获取引用。
在这里您可以阅读更多相关信息:
Constructor synchronization in Java
此外,还有许多关于内存可见性的博客文章。
关于java - 为什么 ArrayBlockingQueue 构造函数在 JDK 8 中需要 Lock,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51781217/