実際、Javaを書く人はCPUとは何の関係もないようです。せいぜい、CPUの実行方法と、前述のスレッドの数を設定する方法と関係があります。ただし、そのアルゴリズムは単なる参照です。多くの異なるシナリオには、それを解決するための実用的な手段が必要です。さらに、CPUを実行した後、CPUをそれほどいっぱいにする方法も検討します。ハハ、人間、それだけです。ハハ、OK、この記事は他のことについてです。たぶん、あなたはほとんどJavaにコードを書いていません。ビジネスを満足させることが最初の重要なことであるため、CPUに注意してください。フレームワークレベルを達成し、多くの共有データキャッシュを含むフレームワークを提供する場合は、中央に多くのデータ要求の問題がある必要があります。もちろん、Javaは多くのクラスの同時パッケージを提供しており、使用することができますが、内部で行う方法は、詳細をよりよく使用するために理解する必要があります。この記事は、これらのコンテンツを焦点として説明しないかもしれません。なぜなら、タイトルパーティーのように、CPU、ハハについてお話したいからです。
同じことが言われていますが、JavaはCPUとは何の関係もないようですので、今何が起こっているのかについて話しましょう。
1.共有要素に遭遇する場合、私たちの最初のアイデアは、揮発性、つまり絶対的な可視性を通じて一貫した読み取り操作を確保することです。いわゆる可視性は、このデータを使用するたびに、CPUはキャッシュコンテンツを使用せず、メモリからデータを取得することを意味します。このプロセスは依然として複数のCPUに対して有効です。つまり、CPUとメモリは現時点で同期されています。 CPUは、+0のようにaddl 0をlock addl 0に類似したアセンブリ命令を発行しますが、何に関連しても何もしません。ただし、命令が完了すると、後続の操作は、この要素の他のスレッドのアクセスに影響を与えなくなります。これは、達成できる絶対的な可視性ですが、一貫した操作を実装できません。つまり、Volatileが達成できないのは、I ++操作が分解されるため、I ++(複数のスレッドの下での同時性)などの操作の一貫性です。
int tmp = i; tmp = tmp + 1; i = tmp;
これらの3つのステップが完了します。この時点から、I ++が最初に他のことを行うことができる理由を確認してから、それ自体に1を追加することができます。
2.マルチスレッドの並行性の一貫性を使用する場合は、ロックメカニズムを使用する必要があります。現在、Atomic*のようなものは基本的にこれらの要件を満たすことができます。多くの安全でないクラスの方法が内部で提供されています。絶対的な可視性データを常に比較することにより、取得したデータが最新であることを確認できます。次に、他のCPUの問題について説明し続けます。
3。過去には、CPUを埋めるためにCPUを実行することはできませんでしたが、どのようにしてメモリとCPUの間の遅延を無視し始めたとしても、満足していませんでした。今日言及したので、遅延について簡単に説明します。一般的に言えば、現在のCPUには3レベルのキャッシュがあり、遅延は年齢によって異なります。そのため、特定の数はほぼ正当なだけです。今日のCPUは一般に1-2NSの遅延があり、第2レベルのキャッシュは一般に数nsから約10 ns、3番目のレベルのキャッシュは一般に30nsから50nsの間であり、メモリアクセスは一般に70nsに達します(コンピューターは非常に速くなり、この値は範囲参照のデータのみです)。この遅延は非常に少ないが、すべてナノ秒レベルであるため、プログラムが命令操作に分割されると、多くのCPUインタラクションがあることがわかります。各相互作用の遅延が非常に大きい場合、現時点ではシステムのパフォーマンスが変わります。
4。今言及された揮発性に戻ります。メモリからデータを取得するたびに、キャッシュを放棄します。もちろん、一部のシングルスレッド操作で遅くなると、遅くなります。時々私たちはこれをしなければなりません。読み取りおよび書き込み操作でさえ一貫性が必要であり、データブロック全体が同期されます。ロックの粒度をある程度減らすことしかできませんが、まったくロックすることはできません。 CPUレベル自体でさえ、命令レベルの制限があります。
5。CPUレベルでの原子運転は、一般に、読み取り障壁、書き込み障壁などを備えた障壁と呼ばれます。それらは一般に1つのポイントで引き起こされます。プログラムの複数の指示がCPUに送信されると、プログラムの最終順序で一貫性があることが保証できる限り、プログラムの順序でいくつかの指示が実行されない場合があります。ソートの観点から、JITはランタイム中に変更され、CPU命令レベルも変更されます。主な理由は、ランタイムの指示を最適化して、プログラムをより速く実行することです。
6. CPUレベルは、メモリ上のキャッシュラインを動作させます。いわゆるキャッシュラインは、一般的にCPUモデルとアーキテクチャに関連するメモリの一部を継続的に読み取ります。現在、多くのCPUは通常、毎回連続メモリを読み取り、初期のメモリは32バイトを持っているため、いくつかの配列を横断すると高速になります(列のトラバーサルに基づいて非常に遅い)が、これは完全に正しくありません。以下は、反対の状況を比較します。
7. CPUがデータを変更した場合、データの変更の状態について説明する必要があります。すべてのデータが読み取られると、複数のCPUの下の複数のスレッドによって並行して読み取ることができます。データブロックで操作を作成するとき、それは異なります。データブロックには、排他的、変更された、無効化およびその他の状態があり、変更後にデータは自然に失敗します。複数のスレッドが複数のCPUの下で同じデータブロックを変更している場合、CPU間のバスデータコピー(QPI)が発生します。もちろん、同じデータに変更した場合、選択肢はありませんが、ポイント6のキャッシュラインに戻ると、問題はより面倒です。データが同じ配列上にあり、配列内の要素が同時にCPUにキャッシュされる場合、マルチスレッドのQPIが非常に頻繁に発生します。アレイで組み立てられたオブジェクトが組み立てられている場合でも、次のような問題が発生する場合があります。
クラスinputinteger {private int value; public inputinteger(int i){this.value = i;}} inputinteger [] integers = new inputinteger [size]; for(int i = 0; i <size; i ++){integers [i] = new inputinteger(i);}現時点では、整数内のすべてがオブジェクトであり、配列上のオブジェクトへの参照のみがあることがわかりますが、オブジェクトの配置は理論的に独立しており、継続的に保存されません。ただし、Javaがオブジェクトメモリを割り当てると、エデンエリアで継続的に割り当てられることがよくあります。 forループの場合、他のスレッドにアクセスされない場合、これらのオブジェクトは一緒に保存されます。彼らが古いエリアへのGCであっても、それはまとめられる可能性が非常に高いです。したがって、単純なオブジェクトに依存してキャッシュラインを解くことによって配列全体を変更する方法は、4バイトであるため、信頼できないように思われます。 64モードの場合、このサイズは24バイト(4バイトが満たされています)で、ポインター圧縮は16バイトです。つまり、CPUは毎回3〜4個のオブジェクトに一致させることができます。 CPUキャッシュの作成方法ですが、システムのQPIには影響しません。 GCプロセスメモリコピープロセスが一緒にコピーされる可能性が高いため、オブジェクトを分離して完成することを考えないでください。最良の方法は、それを埋めることです。それはちょっとしたメモリ無駄ですが、これは最も信頼できる方法であり、オブジェクトを64バイトに埋めることです。ポインター圧縮が有効になっていない場合、24バイトがあり、現時点では40バイトがあります。オブジェクト内に5つのロングを追加するだけです。
クラスinputinteger {public int value; private long a1、a2、a3、a4、a5;}ハハ、この方法は非常に素朴ですが、非常にうまく機能します。時々、JVMがコンパイルされると、これらのパラメーターが実行されていないことがわかります。そのため、直接殺されます。最適化は無効です。メソッドとメソッドは、これらの5つのパラメーターをメソッド本体(すべて使用)で単純に操作することですが、このメソッドはそれを呼び出すことはありません。
8。CPUレベルでは、最初に行うことを行うことができない場合があります。それは王です。 Atomicintegerfieldupdaterの操作では、単一のスレッドでgetanteset(true)を呼び出すと、非常に速く実行され、マルチコアCPUの下で速度が低下し始めます。なぜそれははっきり上記で言われているのですか? GetAndsetが変更され、比較され、最初に変更されるため、QPIは非常に高くなるため、現時点では最初に操作を取得してから変更することをお勧めします。また、一度取得する良い方法でもあります。取得できない場合は、他のスレッドを他のことをしてもらいましょう。
9.時には、忙しくて忙しくないCPUの問題を解決するために、解決すべき多くのアルゴリズムがあります。たとえば、numaはソリューションの1つです。ただし、特定のシナリオでどのアーキテクチャがより有用であっても、すべてのシナリオで効果的ではない場合があります。 CPU状態管理を完了するにはキューロックメカニズムがありますが、状態が頻繁に変更され、さまざまなアプリケーションのコアがCPUと協力するために行うためにいくつかのアルゴリズムを生成するため、CPUラインの問題もあります。
これについては、通常の可変ループの重ね合わせ、揮発性タイプ、アトミック*シリーズなど、多くの詳細がありますが、これは完全に異なります。さまざまな緯度で後方にループする多次元配列ループがあり、多くの詳細があり、実際の最適化プロセスにインスピレーションがある理由を理解しています。ロックの詳細は薄くてめまいがします。システムの一番下のレベルでは、常に軽量の原子操作があります。誰が彼のコードにロックを必要としないと言っても、最高のものはCPUが各瞬間に1つの命令のみを実行できるのと同じくらい簡単です。マルチコアCPUには、読み取りレベル、書き込みレベル、メモリレベルなどを含むバスレベルでいくつかのコンテンツを制御する共有エリアもあります。さまざまなシナリオで、ロックの粒度は可能な限り削減されます。システムのパフォーマンスは自明であり、通常の結果です。