我在一个内部类上有以下方法,我用它来对多线程应用程序中的多个集合进行排序。我想确保每个集合在排序时都是同步的(我已经在我迭代的其他地方同步了)。
注意:其中一个集合支持 ListView 的适配器。
private void sort(List<...> collection) {
if (collection != null) {
Collections.sort(collection, ...);
}
}
问题是如果我包装 synchronised(collection) { Collections.sort }
IDE 警告我同步方法参数是不安全的。
我知道这是一个新引用,但该引用仍然指向原始集合,这样安全吗?如果没有,有没有办法测试集合是否被锁定? (所以我可以在误用时抛出异常)
最佳答案
我认为这里的问题是应该如何访问这些集合。 例如,如果您想要多次读取并且只有一个写入线程到集合中,您应该使用包装类和 ReentrantReadWriteLock:
public class ListWrapper {
private final ArrayList<String> theList = new ArrayList<String>();
private final ReadWriteLock rwl = new ReentrantReadWriteLock();
private final Lock r = rwl.readLock();
private final Lock w = rwl.writeLock();
public String read() {
r.lock();
try {
System.out.println("reading");
if(theList.isEmpty()) {
return null;
}
else {
return theList.get(0);
}
} finally {
r.unlock();
}
}
public void write(String data) {
w.lock();
try {
System.out.println("Written " + data);
theList.add(data);
} finally{
w.unlock();
}
}
}
与内部有列表但不直接公开列表的包装类相同。
public class ListWrapper {
private final List<String> obj;
public ListWrapper (Object obj) {
this.obj = obj;
}
public List<String> getList() {
return obj;
}
}
上面的类是线程安全的,因为它不对被包装的对象进行任何操作。 类包装的对象可能是线程安全的,也可能不是线程安全的,因为返回包装对象的引用后,多个线程可以对该对象进行操作。
因此,被包装对象本身是否线程安全取决于被包装对象的类是如何实现的。
你也可以使用
CopyOnWriteArrayList
其中是 ArrayList 的线程安全变体,其中所有可变操作都是通过制作底层数组的新副本来实现的。
我认为这取决于实现。
关于java - 如何确保传递给方法的集契约(Contract)步?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43191011/