实际上不需要同步构造函数,因为它会锁定正在构造的对象,通常在该对象的所有构造函数完成工作之前,其他线程无法使用它。
上方是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();
}
}
答案 0 :(得分:2)
评论// Lock only for visibility, not mutual exclusion
告诉您。根据CPU的不同,我们可能会遇到以下情况:构造线程“离开”了构造函数,但尚未初始化字段(因此,在示例中,线程离开了ArrayBlockingQueue
构造函数,而我们的count
,{{1} },putIndex
字段尚未初始化,并且其他一些线程已使用items
/ offer
方法启动)。 add
中使用了相同的锁定策略。而且,JVM具有在我们的方法/构造函数中对字节码指令重新排序的功能。最后,可能存在这样的情况,一个线程可以在另一个线程完成构造对象之前获得引用。
在这里您可以阅读有关它的更多信息:
Constructor synchronization in Java
而且,还有许多有关“内存可见性”的博客文章。