假设我有这样的代码块:
List<Integer> lst = Collections.synchronizedCollection(new ArrayList<>());
我有以下两种方法:
public Integer returnFirst() {
lst.get(0);
}
public void iterate() {
synchronized(lst) {
Iterator i = lst.iterator();
while (i.hasNext()) {
System.out.println(i);
}
}
}
假设一个线程调用iterate(),然后另一个线程调用returnFirst()。returnFirst()会被阻塞,因为你在迭代中同步List对象,而迭代当前正在运行?
是。看看SynchronizedCollection
的构造函数和SynchronizedList#get
的方法:
SynchronizedCollection(Collection<E> c) {
this.c = Objects.requireNonNull(c);
mutex = this;
}
public E get(int index) {
synchronized (mutex) {return list.get(index);}
}
您可以看到用于控制并发访问的内部互斥锁实际上是对象本身(mutex = this
),这意味着iterate()
方法中的lst.get(0)
和synchronized(LST)
争夺同一个锁:对象本身。
另外,你的代码将无法编译,将synchronizedCollection
替换为synchronizedList
。
简单代码测试:
public static void main(String[] args) throws InterruptedException {
List<Integer> list = Collections.synchronizedList(new ArrayList<>());
list.add(1);
new Thread(() -> {
try {
synchronized(list) {
Thread.sleep(5000);
Iterator i = list.iterator();
while (i.hasNext()) {
System.out.println(i.next());
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
Thread.sleep(100);
new Thread(() -> {
// It will block for 5 seconds and then output
System.out.println(list.get(0));
}).start();
}
是的,你是对的。returnFirst
将不会运行,直到iterate
完成。