すべてに沿って、CPU、メモリなど、I / Oの速度、CPU>メモリに大きな違いがあります> I / O。これら三つの、コンピュータアーキテクチャ、オペレーティング・システムとの間の差のバランスを取るために、コンパイラは主に反映され、多大な貢献をしました。
1.バランスをとるために、CPUのキャッシュとメモリの速度差を増やします
2.コンパイラの最適化、命令の実行順序、キャッシュは、より合理的な利用できるように
3.オペレーティングシステムプロセス、スレッド、時分割多重CPU、CPUにした後、Iの平衡速度の増加/ O
最適化の上にプログラム全体のパフォーマンスが向上するだけでなく、私たちの並行プログラムに、CPUの使用率を向上させるいくつかの問題を引き起こしありません
1. CPUキャッシュの可視性の問題によって引き起こされます
シングルコア時に、一つだけのCPUとCPUキャッシュは、別のスレッドが同じキャッシュに対応し、視認性が問題ではありません。マルチコア時代には、すべて単一のCPUは独自のキャッシュを持って、別のスレッドの動作が異なるキャッシュかもしれません。例えば、CPU1のキャッシュ動作をスレッドが、スレッドBの動作はCPU2のキャッシュであり、この時点でスレッド変数のV Aの操作は、スレッドのBが表示されていないことは明らかです
注文によって引き起こさ2.コンパイラの最適化問題
不要なCPUのポーズを削減しながら、時には文の順序を変更し、コンパイラの性能を最適化するためには、それだけで、より合理的な使用のCPUキャッシュされません。そして、最適化コンパイラは、我々は一貫マルチスレッドセマンティクスを保証することはできません、同じシリアルセマンティクスを保証することができます。Javaの古典的な例ではシングルトンオブジェクトを作成し、ダブルチェックロックを使用することです。
パブリック クラスシングルトン{ 静的シングルトンインスタンス。 静的シングルトンのgetInstance(){ 場合(例えば== NULL ){ 同期(シングルトンクラス){ 場合(例えば== NULL ) インスタンス = 新しいシングルトン()。 } } 戻りインスタンス。 } }
new演算子の問題点は、new演算子をへの命令の実行のため、最適化されています。
1.メモリMを割り当て
2.アドレスMは、インスタンス変数に割り当てられています
インスタンス変数初期化メモリM 3.
実行のスレッドは、それが直接インスタンスインスタンスを返し、I getInstanceメソッドは、命令2を実行した後、Bのスレッドが実行を開始し、最初の時間が== nullが偽であるBのインスタンスことが分かっているものとするが、この時点では、初期化まだインスタンスインスタンスれていませんこのときBスレッドアクセスインスタンスのメンバ変数がNULLポインタ例外を引き起こす可能性
原子によって引き起こさ3.スレッドの切り替えの問題
线程的切换是由操作系统来处理的,而操作系统走切换是能够发生在任何一条cpu执行完成的。而很多高级语言的一条语句对应cpu指令,count++这个操作则需要三条指令
- 指令1:将count从内存load到cpu寄存器中
- 指令2:将寄存器中的count进行+1
- 指令3:将count写入内存
当线程A执行完指令1后,切换到线程B则发生原子性问题