マルチスレッド環境で使用される並行リストがあります。List が構築されると、ほとんどの操作はそれを走査します。次の2つの方法のどちらがより効率的か、または同期を使用する場合と比較して新しいリストを作成するコストはいくらですか? それとも他にもっと良い方法があるのでしょうか?
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 のスナップショットを取得するため、スレッドセーフです。ただし、sharakan が指摘しているように、コストは 2 つのリストを反復し、ローカル オブジェクト ArrayList を作成することであり、元のリストが大きい場合はコストがかかる可能性があります。
getAllValue2(): 同期ブロックでもスレッドセーフです。(他の関数が適切に同期を行うと仮定します。) 同期ブロックに配置する理由は、.size() 呼び出しが反復と確実に同期されるように、配列を事前に割り当てたいためです。(反復部分は CopyOnWriteList を使用するため、スレッドセーフです。) ただし、ここでのコストは、同期ブロックを使用する機会コストです。getAllValue2() を呼び出すクライアントが 100 万ある場合、それぞれが待機する必要があります。
したがって、答えは、データを読み取る必要がある同時ユーザーの数に大きく依存すると思います。多くの同時ユーザーがいない場合は、おそらく method2 の方が優れています。それ以外の場合は、method1 の方が適しています。同意?
私の使用法では、いくつかの同時クライアントがあり、おそらく method2 が優先されます。(ところで、私のリストは約 10k サイズです)。