理論的論文 - Javaの並行プログラミングは、揮発性の命令の再配置を確認します
volatileキーワードの広範な使用の下でJavaクラスと契約。導入による記事の前に、我々はすでに揮発性の三の大特徴を知っていない:共有変数の可視性を、保証の原子を、オーダーの禁止命令の並び替え後。我々は最初の二つの特性の検証コードを渡す前の二つの記事では、この記事では、我々は秩序を保証並べ替え命令を禁じ確認します。
ライブ命令の並べ替えの例
レストラン所定の位置に移動します。レストランに行くための仮説、レストラン受付B、Cおよび付随ボスD. 唯一の場合はあなたがまたはサーバにまたは第2のテーブルが半分以上時間後に、予約したと言うために上司にフロントデスクを与えたときに食べてもらうことができます。レストランでは、あなたが2時間順に夕食に行く人です。OK、問題はないので、おろか、時間の2つのテーブルまたはあなたを待っている時間半を待ちます。
しかし、今の食事のピークであれば、多くの人が食べに来て、あなたがフロントデスクを言う、ちょうど第2のテーブルの誰を見ていないし、食べるために通行人があり、この時間フロントデスクアテンダントが使用中だったか、上司にノーを言うために時間がありません、所有者やウェイターは彼が夕食のために2つのテーブルを座らせて。あなたが入って来たときにそう、そう、それは第2のテーブルとなっています。あなたのためのこの時間は、結果はあなたが望むものではありません。
この場合は、分析の観点から、コンピュータ実行命令場合は、予想される結果である第2号、にテーブルを食べなければなりません。レストランAは、ウェイターボスCコンパイラと同等であり、Dは、命令メモリシステムであり、プロセッサBの受信と同等です。あなたが時間内に所定のポイントを食べた場合、それは人々が夕食のA.のためにレストランに行くのピークではありませんか その後、スレッドと同等のものを持っています。シングルスレッドです。ボスは、フロントデスクの係員配置ができますか。あなたが唯一の第2だから、間違いなくあなたの机です。これは、シングルスレッドの場合です。期待される結果は実際の結果と一致します。
あなたは(多くのスレッド)、所定の時点でピーク期間での夕食に多くの人々を食べる場合は、この時間内にはレストランが利益のために、またはそれは、フロントデスクの受付または上司であるかどうかは、あなたの場所の順序を変更します。あなたが来ていないときは、所定の位置を食べるために、他の人が手配します。夕食のために他のあなたの代わりに誰かがいる場合、あなたは夕食に来て、この時間は、実際の結果と期待が違いを作るのですか。この時間は、レストランでは、適切な補償をしなければなりません。補償のこの問題に対処するためには、上司が計画を考えました。滞在中は、テーブルの上に看板を予定。
現在の駅やテーブルの上に置くこのブランドを参照するにはウェイターや上司が、私はこの位置が動員することはできません知っています。テーブルの上に記号はメモリバリアの特殊なタイプです。
次のように図です。
ここでも、より一般的な例を与えます:
試験では、先生が最初にやるだろうか、教えてしまうの試験は、行うの背後に置かないでください。試験問題は、彼らの実際の状況に応じて可能性の高い順になる質問順序の話題教師アウトは1-5であると仮定すると、しかし、やっていることは1,2,4,5,3または1,3,4,5,2というようにです。トピックとプログラマがコードを記述することを教師ののこぎりは、タイトルシーケンスが線でコード行の順である場合は、あなたの教師は教師がコンパイラの同等であるこの時点で、行われます、あなたが最初に行うことを教えてくれる、一度にソートされています。次に、あなたはあなた自身のプロセッサを並べ替えると、ソートのと同等であるだろうか。
実際の生活の中で2例以上、私たちは、問題を並べ替えコンピュータ命令を見て見つける、理解しやすいです。
命令の並べ替え
私たちのプログラマはコードの後、コンパイラやプロセッサ命令が再注文にコンパイルされ、JVMは、パフォーマンスを向上させるために、ときに実行されるコードを記述します。3種類に分かれて:
1:コンパイラの最適化並べ替え:
コンパイラの前提を最適化することシングルスレッドのセマンティクスの場合、刑の執行の順番を並べ替え、変更しないことを確実にするためです。
2:命令の並列並び替え:
データ依存のコードはいくつかのステートメントの間に存在しない場合、プロセッサは、ステートメントに対応する機械語命令の順序を変更することがあり
如:int x = 10;int y = 5;对于这种x y之间没有数据依赖关系的,机器指令就会进行重新排序。但是对于:int x = 10; int y = 5; int z = x+y;这种的,因为z和x y之间存在数据依赖(z=x+y)关系。在这种情况下,机器指令就不会把z排序在xy前面。
3:内存系统的重排序
通过之前的学习,我们知道了处理器和主内存之间还存在一二三级缓存。这些读写缓存的存在,使得程序的加载和存取操作,可能是乱序无章的。
指令重排序的流程图
通过上面介绍,我们可以知道从程序员写的Java源码到处理器真正实际执行的指令序列,会经历如下图的过程:
执行顺序:
源码编译器优化重排序(第一次排序) 指令重排序(第二次)内存重排序(第三次) 最终指向的指令。
无论是第一次编译器的重排序还是第二、三次的处理器重排序。这些重排序当在多线程的场景下可能会出现线程可见性的问题。
如在多线程的情况下,单例模式就不安全了。
为了解决这个问题,JMM允许编译器在生成指令顺序的时候,可以插入特定类型的内存屏障来禁止指令重排序。
当一个变量使用volatile修饰的时候,volatile关键字就是内存屏障。当编译器在生成指令顺序的时候,发现了volatile,就直接忽略掉。不再重排序了。
示意图:
证明volatile禁止指令重排演示代码,欢迎继续学习下一篇文章
欢迎关注凯哥公众号:凯哥Java(kaigejava)