Java EE 勉強会 (第40回)
Java 並行処理プログラミング
第12章「並行プログラムを試験する」。担当は杉田さん。
並行プログラムの自動テストの方法はなかなか興味深かった。
帰宅後の検証結果もあわせてメモ。
P.282 の List 12-3 はブロックしなくてもエラーにならないのでは? by 和泉さん
void testTakeBlocksWhenEmpty() { final SemaphoreBoundedBuffer<Integer> bb = new SemaphoreBoundedBuffer<Integer>(10); Thread taker = new Thread() { public void run() { try { int unused = bb.take(); fail(); // ここに来たら、エラー } catch (InterruptedException success) {} }}; try { taker.start(); Thread.sleep(LOCKUP_DETECT_TIMEOUT); taker.interrupt(); taker.join(LOCKUP_DETECT_TIMEOUT); assertFalse(taker.isAlive()); } catch (Exception unexpected) { fail(); } }
確かに、fail() は呼ばれるけれど、taker のスレッドが落ちるだけで、JUnit 上ではエラーにならない。あと、テストメソッドは public にしないと。例えば、こんなふうに書く必要がある。
public void testTakeBlocksWhenEmpty() { final SemaphoreBoundedBuffer<Integer> bb = new SemaphoreBoundedBuffer<Integer>(10); final boolean[] failed = new boolean[1]; Thread taker = new Thread() { public void run() { try { int unused = bb.take(); failed[0] = true; // ここに来たら、エラー } catch (InterruptedException success) {} }}; try { taker.start(); Thread.sleep(LOCKUP_DETECT_TIMEOUT); taker.interrupt(); taker.join(LOCKUP_DETECT_TIMEOUT); assertFalse(taker.isAlive()); // ここで検証 assertFalse(failed[0]); } catch (Exception unexpected) { fail(); } }
P.288 の List 12-7 で「ヒープをスナップショットする」の詳細は?
class Big { double[] data = new double[100000]; } void testLeak() throws InterruptedException { BoundedBuffer<Big> bb = new BoundedBuffer<Big>(CAPACITY); int heapSize1 = /* ヒープをスナップショットする */; for (int i = 0; i < CAPACITY; i++) bb.put(new Big()); for (int i = 0; i < CAPACITY; i++) bb.take(); int heapSize2 = /* ヒープをスナップショットする */; assertTrue(Math.abs(heapSize1 - heapSize2) < THRESHOLD); }
標準 API だけでやろうとすると、例えばこんな感じ?
private int snapshotHeap() { System.gc(); Runtime r = Runtime.getRuntime(); long total = r.totalMemory(); long free = r.freeMemory(); long heap = total - free; return (int) heap; }
勉強会でも話題になっていたけれど、System.gc() は比較的ちゃんと GC してくれる。
ただし、元の testLeak() だと、heapSize1 より heapSize2 の方が小さくなってしまうことが多いみたい。heapSize1 の前にも、メモリを大量に使用する処理を入れると良さそう。
public void testLeak() throws InterruptedException { BoundedBuffer<Big> bb = new BoundedBuffer<Big>(CAPACITY); // ここから、 for (int i = 0; i < CAPACITY; i++) bb.put(new Big()); for (int i = 0; i < CAPACITY; i++) bb.take(); // ここまで追加 int heapSize1 = snapshotHeap(); for (int i = 0; i < CAPACITY; i++) bb.put(new Big()); for (int i = 0; i < CAPACITY; i++) bb.take(); int heapSize2 = snapshotHeap(); assertTrue(Math.abs(heapSize1 - heapSize2) < THRESHOLD); }
P.289 の List 12-9 で、
ExecutorService exec = Executors.newFixedThreadPool(MAX_SIZE);
は、引数に threadFactory を渡してあげないとダメ。
ExecutorService exec = Executors.newFixedThreadPool(MAX_SIZE, threadFactory);
12-2-3「応答性を計測する」で、公平モードにすると、不公平モードの最大値よりも時間がかかってしまう。何でも公平にするってことはコストがかかるんだなぁと思った。
LDAP でとらぶった時
by 和泉さん
パラメータの設定の仕方とか、NamingEnumeration はちゃんと close しようとか。