在列表上同步

Synchronize on List

假设我有这个代码块:

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 对象,并且迭代当前为 运行?

是的,你是对的。在 iterate 完成之前,returnFirst 不会 运行。

是的。 看看 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),这意味着你的[=18=中的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();
    }