Windows Vista 64bit版上で、JDK 1.6 x86/x64版をインストールして、64bit版の能力を探ってみました。
実験環境の構成
CPU | AMD Athlon 64 x2 4200+ |
---|---|
メモリ | 2GB |
OS | Windows Vista Ultimate 64bit |
JVM | Sun JDK 1.6 U2(1.6.0_02) |
64bit長のデータアクセス
2つのスレッドを並列実行させ(デュアルコアPC)、スレッド間で共有する64bitプリミティブ型(long)を排他制御なしに1つのスレッドがwriteしもう1つのスレッドがreadし、意図しない値(32bitで分断)が観測されるか否かを実験しました。writeスレッドは、共有変数に次の2つの値を交互に書き込み続けます。
- 0xAAAAAAAAAAAAAAAA
- 0x5555555555555555
readスレッドは、共有変数から読み込んだ回数と、読み込んだ値が上記2つに該当しない回数を計測します。
計測結果
JDK 6(x86) | JDK 6(x64) |
---|---|
21万回/10億回中 | 0回/31億回中 |
JDKの64bit版実装では、longのアクセスが32bitで分断されることはないようです。
以下が実験コードです。
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class VolatileReaderWriter { private static long sharedValue; private final static long WRITE_VALUE_1 = 0xaaaaaaaaaaaaaaaaL; private final static long WRITE_VALUE_2 = 0x5555555555555555L; static class Writer implements Runnable { public void run() { boolean isOne = true; while (true) { sharedValue = isOne ? WRITE_VALUE_1 : WRITE_VALUE_2; isOne = !isOne; } } } static class Reader implements Runnable { private long numTotal; private long numFailure; public void run() { while (true) { numTotal++; long readValue = sharedValue; if (readValue != WRITE_VALUE_1 && readValue != WRITE_VALUE_2) { System.out.printf( "不正値を読み込み:%x (%d/%d)%n", readValue, ++numFailure, numTotal ); } } } synchronized long getNumTotal() { return numTotal; } synchronized long getNumFailure() { return numFailure; } } static class Hook extends Thread { private Reader reader; public Hook(Reader aReader) { reader = aReader; } public void run() { System.out.println("Now shuttin down VolatileReaderWriter Program"); System.out.println("Total number = " + reader.getNumTotal()); System.out.println("Failure count = " + reader.getNumFailure()); } } public static final void main(final String[] args) { ExecutorService service = Executors.newCachedThreadPool(); Writer writer = new Writer(); service.execute(writer); Reader reader = new Reader(); service.execute(reader); Runtime.getRuntime().addShutdownHook(new Hook(reader)); } }
スレッド生成最大数
スレッドをどんどん生成し、スレッド生成可能個数の上限を実験しました。
スレッドが終了しないように、CyclicBarrierでawaitして待たせるコードにしています。
計測結果
JDK 6(x86) | JDK 6(x64) |
---|---|
3071個 | 2万個 |
JDK 32bit版では、OutOfMemoryError: unable to create new native thread のエラーが発生します。
JDK 64bit版では、2万個を越えたあたりでPCのメモリ搭載量を越えるようになり、スワップのためシステム全体が非常に重くなりますが、エラーは発生しません。
したがって、物理メモリを増やせば、さらに上限個数が増えるものと考えます。
以下に実験コードを示します。
import java.util.concurrent.CyclicBarrier; import java.util.concurrent.BrokenBarrierException; public class UnboundThreadCreator3 { public static final void main(final String[] args) { if (args.length < 1) { System.err.println("Usage: java UnboundThreadCreator3 <NumThreads>"); System.exit(-1); } int numThreads = Integer.parseInt(args[0]); System.out.println("Number of Thread = " + numThreads); final CyclicBarrier barrier = new CyclicBarrier(numThreads); for (int i=0; i<numThreads; i++) { Thread thread = new Thread(new Runnable() { public void run() { int count = 10; while (count > 0) { try { count--; Thread.sleep(1000); } catch (InterruptedException e) { break; } } try { barrier.await(); } catch (InterruptedException e) { System.err.println("Interrupted when awaiting"); } catch (BrokenBarrierException e) { System.err.println("Broken barrier when awaiting"); } } } ); thread.start(); } } }