Javaマルチスレッドの理解
OSでのプロセス、スレッドプロセス:実行中のプログラムであり、開いているファイル、保留中の信号、カーネル内部データ、プロセッサ状態、カーネルアドレス空間、1つ以上の実行スレッド、データセグメントなどの他のリソースが含まれます. スレッド:プロセス内のアクティブなオブジェクト、カーネルスケジューリングのオブジェクトはプロセスではなくスレッドです.従来のUnixシステムのプロセスには、1つのスレッドしか含まれていません.
Linuxでのスレッドの実装
Linuxカーネルの観点からはスレッドという概念はありません.Linuxはすべてのスレッドをプロセスとして実現し,カーネルはスレッドに特別なスケジューリングアルゴリズムと特別なデータ構造を用意していない.スレッドは、他のプロセスとリソースを共有するプロセスとしてのみ見なされます.だから、カーネルから見れば、それは普通のプロセスです.
WindowsやSolarisなどのオペレーティングシステムの実装では、スレッドを専門にサポートするメカニズムが提供されています(
書き込み時コピー
従来のfork()システム呼び出しは、コピーされたデータが不要である可能性があるため、すべてのリソースを直接新しく作成されたプロセスにコピーします.
Linuxのfork()は,書き込み時コピーを用いて実現する.カーネルは、プロセスアドレス空間全体をコピーするのではなく、親プロセスとサブプロセスにコピーを共有させます.
書き込みが必要な場合にのみデータがコピーされ、それ以前は読み取り専用で共有されていました.この最適化は、まったく使用されないデータの大量コピーを回避することができる(アドレス空間は、しばしば数十Mのデータを含む).
したがって,Linux作成プロセスとスレッドの違いは,共有アドレス空間,ファイルシステムリソース,ファイル記述子,信号処理プログラムなどである.
以下はStackOverflowの答えです.
すなわち、
JavaスレッドをOSスレッドにマッピングする方法
JVMはlinuxプラットフォーム上でスレッドを作成し、pthreadインタフェースを使用する必要があります.pthreadはPOSIX規格の一部であり、スレッドを作成および管理するC言語インタフェースを定義している.Linuxはpthreadの実装を提供します. である. です. である. である.
戻り値なしスレッドと戻り値付きスレッド戻り値なし:1つはThreadを直接継承することであり、もう1つはRunnableインタフェース を実装することである.帯域戻り値:CallableとFutureで を実現
戻り値を持つスレッドは、実際にはより一般的に使用されています.
競合条件
ある計算の正確性が複数のスレッドの交互実行タイミングに依存すると,競合条件が発生する.
最も一般的な競合条件タイプは、「先に検査してから実行」(
「チェックしてから実行」を使用する一般的な例は、初期化の遅延です.
そうするな.
Executorフレームワーク
裸スレッドの使用の欠点スレッドのライフサイクルのオーバーヘッドは非常に高いです.スレッドの作成と破棄には代価がありません. リソース消費:メモリとCPUが消費され、大量のスレッドがCPUリソースを競合するとパフォーマンスオーバーヘッドが発生します.すべてのCPUをビジー状態にするのに十分なスレッドがある場合は、より多くのスレッドを作成するとパフォーマンスが低下します. 安定性:作成可能なスレッドの数に制限があります.
Executor基本原理
スレッドプールの構築関数は次のとおりです.
スレッドプールサイズ が直接作成されます.スレッド数は スレッド数は
keep-alive
ワークキュー
ワークキュー(
一般的なワークキューには、次のようなものがあります.直接切替( 無境界キュー( 境界キュー( 生産環境では、キューに蓄積されたタスクが多すぎると、大量のメモリが消費され、最後の
Javaオリジナルスレッドプールの生産環境における問題
サービス化の背景の下で、私たちのフレームワークは一般的に
同じスレッドでRPC呼び出しを同期する場合、問題はありません.しかし、スレッドプールを使用してクライアントの非同期呼び出しを行うと、
この痛みに対して、アリ開源の
パフォーマンスと伸縮性
性能に対する考え方
パフォーマンスの向上は、より少ないリソースでより多くのことをすることを意味します.「リソース」は、
マルチスレッドを使用すると、サービス全体のパフォーマンスが理論的に向上しますが、マルチスレッドを使用すると、単一スレッドに比べて追加のパフォーマンスオーバーヘッドが導入されます.スレッド間の調整(ロック、トリガ信号、メモリ同期など)、コンテキストの増加、スレッドの作成と破棄、スレッドのスケジューリングなどが含まれます.スレッドを過度に使用すると、同じ機能を実現するシリアルプログラムよりもパフォーマンスが低下する可能性があります.
パフォーマンスモニタリングの観点から、CPUはできるだけ忙しい状態を保つ必要がある.プログラムがコンピューティングが密集している場合は、プロセッサを増やすことでパフォーマンスを向上させることができます.しかし、プログラムがCPUをビジー状態に保つことができない場合は、より多くのプロセッサを追加しても始まらない.
伸縮性
伸縮性とは、計算リソース(例えば、CPU、メモリ、記憶容量、IO帯域幅)を増加させると、プログラムのスループットまたは処理能力が応答して増加することを意味する.
プログラム内の表現層、ビジネスロジック層、および永続層は互いに独立しており、異なるサービスによって処理される可能性があるという3層モデルをよく知っています.これは、伸縮性の向上が通常性能損失をもたらすことをよく示しています.パフォーマンス・レイヤ、ビジネス・ロジック・レイヤ、および永続レイヤを単一のアプリケーションに統合すると、負荷が高くない場合、アプリケーションを多層化するよりもパフォーマンスが高くなります.この単体アプリケーションは,異なる階層間でタスクを伝達する際に存在するネットワーク遅延を回避し,多くのオーバーヘッドを低減する.
しかしながら、モノマー応用が自己処理能力の限界に達すると、その処理能力を向上させることは非常に困難であり、水平に拡張できないという深刻な問題に直面する.
Amdahlの法則
ほとんどのコンカレント・プログラムは、一連のパラレル・ワークとシリアル・ワークから構成されています.
Nが無限大に近づくと、最大加速比は
コンテキストの切り替え
スレッドスケジューリングではコンテキストの切り替えが発生し、コンテキストの切り替えではオーバーヘッドが発生します.
以上です.
テキストリンク
https://segmentfault.com/a/11...
Linuxでのスレッドの実装
Linuxカーネルの観点からはスレッドという概念はありません.Linuxはすべてのスレッドをプロセスとして実現し,カーネルはスレッドに特別なスケジューリングアルゴリズムと特別なデータ構造を用意していない.スレッドは、他のプロセスとリソースを共有するプロセスとしてのみ見なされます.だから、カーネルから見れば、それは普通のプロセスです.
WindowsやSolarisなどのオペレーティングシステムの実装では、スレッドを専門にサポートするメカニズムが提供されています(
lightweight processes
).書き込み時コピー
従来のfork()システム呼び出しは、コピーされたデータが不要である可能性があるため、すべてのリソースを直接新しく作成されたプロセスにコピーします.
Linuxのfork()は,書き込み時コピーを用いて実現する.カーネルは、プロセスアドレス空間全体をコピーするのではなく、親プロセスとサブプロセスにコピーを共有させます.
書き込みが必要な場合にのみデータがコピーされ、それ以前は読み取り専用で共有されていました.この最適化は、まったく使用されないデータの大量コピーを回避することができる(アドレス空間は、しばしば数十Mのデータを含む).
したがって,Linux作成プロセスとスレッドの違いは,共有アドレス空間,ファイルシステムリソース,ファイル記述子,信号処理プログラムなどである.
以下はStackOverflowの答えです.
すなわち、
Linux
の下で、プロセスはfork()
を使用して作成され、スレッドはpthread_create()
を使用して作成される.fork()
およびpthread_create()
は、clone()
関数によって実現されるが、伝達されるパラメータが異なる、すなわち共有されるリソースが異なるだけである.(Linux
はNPTL
によってPOSIX Thread
を実現する仕様であり、すなわち軽量レベルのプロセスによってPOSIX Thread
を実現し、以前Unix
にあったライブラリ、ソフトウェアをLinux
にスムーズに移行させることができる)JavaスレッドをOSスレッドにマッピングする方法
JVMはlinuxプラットフォーム上でスレッドを作成し、pthreadインタフェースを使用する必要があります.pthreadはPOSIX規格の一部であり、スレッドを作成および管理するC言語インタフェースを定義している.Linuxはpthreadの実装を提供します.
pthread_t tid;
if (pthread_create(&tid, &attr, thread_entry_point, arg_to_entrypoint))
{
fprintf(stderr, "Error creating thread
");
return;
}
tid
は、新たに作成するスレッドのID attr
は、設定する必要があるスレッド属性thread_entry_point
は、新しく作成するスレッドによって呼び出される関数ポインタarg_to_entrypoint
は、thread_entry_point
に伝達するパラメータthread_entry_point
が指す関数がThreadオブジェクトのrunメソッドである.戻り値なしスレッドと戻り値付きスレッド
戻り値を持つスレッドは、実際にはより一般的に使用されています.
競合条件
ある計算の正確性が複数のスレッドの交互実行タイミングに依存すると,競合条件が発生する.
最も一般的な競合条件タイプは、「先に検査してから実行」(
Check-Then-Act
)操作、すなわち、失効する可能性のある観測結果によって次の動作を決定することである.「チェックしてから実行」を使用する一般的な例は、初期化の遅延です.
public class LazyInitRace {
private ExpensiveObject instance = null;
public ExpensiveObject getInstance() {
if (instance == null) {
instance = new ExpensiveObject();
}
return instance;
}
}
そうするな.
Executorフレームワーク
裸スレッドの使用の欠点
prod
環境では、
の方法には深刻な欠陥があり、特に大量のスレッドを作成する必要がある場合:JVM
の起動パラメータ、オペレーティングシステムのスレッドに対する制限が含まれています.これらの制限を超えると、OutOfMemoryError
の異常が放出される可能性があります.Executor基本原理
Executor
は、生産者-消費者モードに基づいて、タスクをコミットする操作は生産者に相当し、タスクを実行するスレッドは消費者に相当する.スレッドプールの構築関数は次のとおりです.
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
スレッドプールサイズ
corePoolSize
:コアスレッド数、スレッドプールのスレッド数がcorePoolSize
未満の場合、新しいスレッドcorePoolSize
より大きいがmaximumPoolSize
より小さい:タスクキューがまだ満たされていない場合、このタスクはタスクキューの最後に挿入されます.タスクキューがいっぱいになると、このタスクを実行するために新しいスレッドが作成されます.maximumPoolSize
に等しい:タスクキューがまだ満たされていない場合、このタスクはタスクキューの最後に挿入されます.この時点でタスクキューがいっぱいになった場合、RejectedExecutionHandler
によって処理されます.keep-alive
keepAliveTime
:スレッドプール内のスレッド数がcorePoolSize
より大きい場合、スレッドがアイドル(Idle)状態で指定された時間(keepAliveTime
)を超えると、スレッドプールはスレッドを破棄します.ワークキュー
ワークキュー(
WorkQueue
)は、コミットされたタスクを格納するために使用されるBlockingQueue
ですが、実行するためのスレッドがまだ空いていません.一般的なワークキューには、次のようなものがあります.
Direct handoffs
)Unbounded queues
)Bounded queues
)OOM
になるため、無境界キューの使用は禁止されています.通常は固定サイズの境界キューを設定し、スレッドプールがいっぱいで、キューもいっぱいの場合、新しく提出されたタスクを直接拒否し、RejectedExecutionException
を投げ出します.本質的には、サービス自体に対する保護メカニズムであり、サービスが新しい提出されたタスクを処理するリソースがなく、直接拒否するためです.Javaオリジナルスレッドプールの生産環境における問題
サービス化の背景の下で、私たちのフレームワークは一般的に
の機能を統合し、呼び出しチェーン全体を直列に接続するために使用され、主にTraceId
とSpanId
を記録します.TraceId
およびSpanId
は、一般にThreadLocal
に記録され、事業者にとって透明である.同じスレッドでRPC呼び出しを同期する場合、問題はありません.しかし、スレッドプールを使用してクライアントの非同期呼び出しを行うと、
Trace
の情報が失われます.根本的な原因は、Trace
の情報がプライマリスレッドのThreadLocal
からスレッドプールのThreadLocal
に伝達されないことです.この痛みに対して、アリ開源の
transmittable-thread-local
はこの問題を解決したが、実現は難しくない.ソースコードを読むことができる.https://github.com/alibaba/transmittable-thread-local
パフォーマンスと伸縮性
性能に対する考え方
パフォーマンスの向上は、より少ないリソースでより多くのことをすることを意味します.「リソース」は、
CPU
クロックサイクル、メモリ、ネットワーク帯域幅、ディスク領域などの他のリソースを意味します.動作性能が特定のリソースによって制限される場合、通常、CPU密集型、IO密集型など、リソース密集型の動作と呼ぶ.マルチスレッドを使用すると、サービス全体のパフォーマンスが理論的に向上しますが、マルチスレッドを使用すると、単一スレッドに比べて追加のパフォーマンスオーバーヘッドが導入されます.スレッド間の調整(ロック、トリガ信号、メモリ同期など)、コンテキストの増加、スレッドの作成と破棄、スレッドのスケジューリングなどが含まれます.スレッドを過度に使用すると、同じ機能を実現するシリアルプログラムよりもパフォーマンスが低下する可能性があります.
パフォーマンスモニタリングの観点から、CPUはできるだけ忙しい状態を保つ必要がある.プログラムがコンピューティングが密集している場合は、プロセッサを増やすことでパフォーマンスを向上させることができます.しかし、プログラムがCPUをビジー状態に保つことができない場合は、より多くのプロセッサを追加しても始まらない.
伸縮性
伸縮性とは、計算リソース(例えば、CPU、メモリ、記憶容量、IO帯域幅)を増加させると、プログラムのスループットまたは処理能力が応答して増加することを意味する.
プログラム内の表現層、ビジネスロジック層、および永続層は互いに独立しており、異なるサービスによって処理される可能性があるという3層モデルをよく知っています.これは、伸縮性の向上が通常性能損失をもたらすことをよく示しています.パフォーマンス・レイヤ、ビジネス・ロジック・レイヤ、および永続レイヤを単一のアプリケーションに統合すると、負荷が高くない場合、アプリケーションを多層化するよりもパフォーマンスが高くなります.この単体アプリケーションは,異なる階層間でタスクを伝達する際に存在するネットワーク遅延を回避し,多くのオーバーヘッドを低減する.
しかしながら、モノマー応用が自己処理能力の限界に達すると、その処理能力を向上させることは非常に困難であり、水平に拡張できないという深刻な問題に直面する.
Amdahlの法則
ほとんどのコンカレント・プログラムは、一連のパラレル・ワークとシリアル・ワークから構成されています.
Amdahl
の法則は、計算リソースを増加させる場合、
と
が占める割合に応じて、プログラムが理論的に最高加速比を実現できることを記述する.F
が直列に実行されなければならない部分であると仮定すると、Amdahl
の法則に従って、N個のプロセッサを含む機械において、最も高い加速比は以下の通りである.Nが無限大に近づくと、最大加速比は
1/F
に近づく.したがって,プログラムの50%の計算がシリアルで実行される必要がある場合,最高の加速比は2にすぎない.コンテキストの切り替え
スレッドスケジューリングではコンテキストの切り替えが発生し、コンテキストの切り替えではオーバーヘッドが発生します.
CPU
プログラムが大量のスレッド切替を生成すると、システムのスループットが低下する.UNIX
システムのvmstat
コマンドは、コンテキスト切替回数やカーネルでの実行時間の割合などの情報を報告することができる.カーネル占有率が高い(10%を超える)場合、スケジューリングアクティビティは通常頻繁に発生していることを示し、これはI/O
またはロック競合によるブロックに起因する可能性が高い.>> vmstat
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 0 0 3235932 238256 3202776 0 0 0 11 7 4 1 0 99 0 0
cs:
sy:
us:
以上です.
テキストリンク
https://segmentfault.com/a/11...