OCP 試験の演習を行っています。現時点では、複数のスレッドを使用しているときにCopyOnWriteArrayListの内容を出力しようとしました。ドキュメントによると、 CopyOnWriteArrayList のイテレータは
イテレータが作成された時点で存在するリスト内の番号を出力します
そのため、あるスレッドが CopyOnWriteArrayList に書き込みを開始し、別のスレッドが CopyOnWriteArrayListから読み取りを開始すると、(時々) いくつかの項目が出力されると予想されます。書き込みスレッドが終了した後に CopyOnWriteArrayList をトラバースすると、新しいイテレータがすべてのアイテムを出力することが期待されます。
残念ながら、Runnable インターフェイスの匿名実装を使用している場合、これは機能しません。ただし、CopyOnWriteArrayList への参照を渡すカスタム スレッド クラスを使用する場合は機能します。
今のところ、なぜこれが起こるのかわかりません。この効果が発生するかどうかはわかりませんfinal CopyOnWriteArrayList<Integer> intList = new CopyOnWriteArrayList<>();
が、そうである場合は、その理由がまったくわかりません。
このトピックに関するご意見をお待ちしております。
Runnable の匿名実装の使用 - 期待どおりに動作しない
static void copyOnWriteCollections() {
System.out.println("copyOnWriteCollections".toUpperCase());
final CopyOnWriteArrayList<Integer> intList = new CopyOnWriteArrayList<>();
Thread tADD = new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 10000; i++) {
intList.add(i);
}
}
});
tADD.start();
/// will print the numbers in the list which are present
/// at the moment the iterator is created
Thread tREAD = new Thread(new Runnable() {
public void run() {
for (Integer i : intList) {
System.out.print(i);
System.out.print(" ");
}
}
});
tREAD.start();
try {
tADD.join();
tREAD.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
// will print out all numbers - as iterator is created when all
// modifications
// to intList have finished
System.out.println();
new Thread(new Runnable() {
public void run() {
System.out.println("new");
System.out.println("\tsize of intList: " + intList.size());
Iterator<Integer> it = intList.iterator();
while (it.hasNext()) {
int i = it.next();
System.out.print(i);
System.out.print(" ");
}
System.out.println("end");
}
}).start();
}
カスタム スレッド クラスの使用 - 期待どおりに動作します
class CopyOnWriteThread extends Thread {
Iterator<Integer> it = null;
boolean read = false;
CopyOnWriteArrayList<Integer> intList = null;
public CopyOnWriteThread(CopyOnWriteArrayList<Integer> intList, boolean read) {
this.intList = intList;
this.read = read;
}
public void run() {
if (read) {
it = intList.iterator();
System.out.println("START read (" + Thread.currentThread().getName() + ")");
System.out.print("\t");
while (it.hasNext()) {
System.out.print(it.next());
System.out.print(" ");
}
System.out.println();
System.out.println("END read (" + Thread.currentThread().getName() + ")");
} else {
System.out.println("START write (" + Thread.currentThread().getName() + ")");
for (int i = 0; i < 10000; i++) {
intList.add(i);
}
System.out.println("END write (" + Thread.currentThread().getName() + ")");
}
}
}
static void copyOnWriteCollections_CustomThread() {
CopyOnWriteArrayList<Integer> intList = new CopyOnWriteArrayList<>();
CopyOnWriteThread tWRITE = new CopyOnWriteThread(intList, false);
CopyOnWriteThread tREAD = new CopyOnWriteThread(intList, true);
tWRITE.start();
tREAD.start();
try {
tWRITE.join();
tREAD.join();
} catch (InterruptedException e) {
}
CopyOnWriteThread tREAD2 = new CopyOnWriteThread(intList, true);
tREAD2.start();
}
現在、JDK 1.7.0_25 および Eclipse Mars Release 4.5.0 を使用して、Win10 マシンで作業しています。