为所有线程锁定对象?

Lock objects for all threads?

我有这个小代码示例,在修改列表时,我用同步锁定了它,但是在读取列表时它出现了 ConcurrentModificationException,因为没有 "synchronized" 锁无效。是否可以为所有使用对象的线程锁定对象,甚至是非同步线程?

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class Test {

    public static void main(String[] args) {

        final Random r = new Random(System.currentTimeMillis());

        List<Integer> list = new ArrayList<>();

        new Thread(new Runnable() {
            public void run() {
                while (true) {
                    synchronized (list) {
                        list.add(r.nextInt());
                    }
                }
            }
        }).start();

        new Thread(new Runnable() {
            public void run() {
                while (true) {
                    for (Integer i : list) {
                        System.out.println(i);
                    }
                }
            }
        }).start();
    }
}

背景是我不想更改读取对象的代码中的所有部分

您可以考虑使用 List 的并发实现,而不是 ArrayList。也许是 CopyOnWriteArrayList。

final List<Integer> list = new CopyOnWriteArrayList<Integer>();

如果可以修改并发使用该对象的函数,只需在每个临界区添加synchronized

      while (true) {
          synchronized(list){
                for (Integer i : list) {
                      System.out.println(i);
             }
        }
}

如果不能,请创建负责锁定线程的指定锁:

Lock lock = new Lock();
new Thread(new Runnable(){
  //...
     synchronized(lock){
       do unsynchonized function on list
     }
  //...
}).start();

new Thread(new Runnable(){
  //...
     synchronized(lock){
       do unsynchonized function on list
     }
  //...
}).start();

如果其中一个函数已经进行了一些锁定,后者可能会减慢进程,但通过这种方式,您可以确保始终同步对并发对象的访问。

Is it possible to lock an object for all threads which use the object.

一句话,不能。当一个线程进入synchronized(foo) {...}块时,不会阻止其他线程访问或修改foo。它唯一阻止的是,它阻止其他线程同时在同一个对象上进行同步。

可以 做的是,您可以创建自己的 class 来封装锁和锁保护的数据。

class MyLockedList {
    private final Object lock = new Object();
    private final List<Integer> theList = new ArrayList<>();

    void add(int i) {
        synchronized(lock) {
            theList.add(i);
        }
    }

    void printAll() {
        synchronized(lock) {
            for (Integer i : theList) {
                System.out.println(... i ...);
            }
        }
    }

    ...
}