我有一个在多线程环境中使用的并发列表。一旦建立了列表,大部分操作就是遍历它。我想知道以下两种方法中哪一种更有效,或者创建新列表与使用同步的成本是多少?或者也许还有其他更好的方法?
List<Object> list = new CopyOnWriteArrayList<Object>();
public int[] getAllValue1() {
List<Object> list2 = new ArrayList<Object>(list);
int[] data = new int[list2.size()];
int i = 0;
for (Object obj : list2) {
data[i++] = obj.getValue();
}
return data;
}
public int[] getAllValue2() {
synchronized (list) {
int[] data = new int[list.size()];
int i = 0;
for (Object obj : list) {
data[i++] = obj.getValue();
}
return data;
}
}
UPDATE getAllValue1():它是线程安全的,因为它获取 CopyOnWriteList 的快照,而 CopyOnWriteList 本身就是线程安全列表。但是,正如 sharakan 指出的那样,成本是迭代 2 个列表,并创建一个本地对象 ArrayList,如果原始列表很大,这可能会很昂贵。
getAllValue2():在同步块中也是线程安全的。(假设其他函数正确同步。)将它放在同步块中的原因是因为我想预先分配数组,以确保 .size() 调用与迭代同步。(迭代部分是线程安全的,因为它使用 CopyOnWriteList。)但是这里的成本是使用同步块的机会成本。如果有 100 万个客户端调用 getAllValue2(),每个客户端都必须等待。
所以我想答案真的取决于有多少并发用户需要读取数据。如果并发用户不多,可能方法2更好。否则,方法1更好。同意?
在我的使用中,我有几个并发客户端,可能首选方法 2。(顺便说一句,我的清单大约是 10k 大小)。