関与する作業がかなりあるため、Javaスレッドの作成はコストがかかります。
- メモリの大きなブロックを割り当て、スレッドスタックに初期化する必要があります。
- ホストOSでネイティブスレッドを作成/登録するには、システムコールを実行する必要があります。
- ディスクリプタを作成し、初期化して、JVM内部データ構造に追加する必要があります。
また、スレッドが有効である限り、スレッドはリソースを制限するという意味でもコストがかかります。たとえば、スレッドスタック、スタックから到達可能なオブジェクト、JVMスレッド記述子、OSネイティブスレッド記述子。
これらすべてのコストはプラットフォーム固有ですが、これまでに遭遇したどのJavaプラットフォームでも安価ではありません。
Google検索で古いベンチマークが見つかりました。これは、2002ヴィンテージLinuxを実行している2002ヴィンテージデュアルプロセッサXeon上のSun Java 1.4.1で、1秒あたり最大4000のスレッド作成率を報告しています。より最新のプラットフォームでは、より良い数値が得られます...そして、方法論についてはコメントできません...少なくとも、それは、スレッドの作成がどれほど高価になる可能性があるかについての足掛かりを与えます。
Peter Lawreyのベンチマークは、最近ではスレッドの作成が絶対的にかなり高速であることを示していますが、これがJavaやOSの改善によるものか、それともプロセッサの速度が速いかは不明です。しかし、彼の数字はまだあなたが作成/新しいスレッドを毎回開始対スレッドプールを使用する場合150+倍の改善を示しています。(そして、これはすべて相対的であると彼は主張します...)
(上記は「グリーンスレッド」ではなく「ネイティブスレッド」を想定していますが、最新のJVMはすべてパフォーマンス上の理由からネイティブスレッドを使用します。グリーンスレッドは作成にコストがかかる可能性がありますが、他の分野では有料です。)
Javaスレッドのスタックが実際に割り当てられる方法を確認するために、少し掘り下げました。Linux上のOpenJDK 6の場合、スレッドスタックはpthread_create
、ネイティブスレッドを作成するへの呼び出しによって割り当てられます。(JVMはpthread_create
事前に割り当てられたスタックを渡しません。)
次に、pthread_create
スタック内でmmap
次のように呼び出して割り当てられます。
mmap(0, attr.__stacksize,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)
によるとman mmap
、MAP_ANONYMOUS
フラグはメモリをゼロに初期化します。
したがって、(JVM仕様に従って)新しいJavaスレッドスタックをゼロにする必要はないかもしれませんが、実際には(少なくともLinux上のOpenJDK 6では)ゼロになっています。