アート並行プログラミング - ノート(B)

序文

JavaのバイトコードにJavaコードをコンパイルした後、バイトコードのクラスはJVM、JVMバイトコード実行にロードされ、CPUの最終アセンブリ命令の実行に変換する必要があり、複雑なメカニズムは、Javaに依存して使用JVMの実装とCPU命令。この章では、との下部にある深さに探求する実装の原則の基礎となるのJava並行処理メカニズム

問題

揮発性とは何ですか
同期した基準との原則
Javaオブジェクトヘッドロックアップグレードプロセスは何ですか?どのようなバイアスがロックしている
アトミック操作とは何ですか?アトミック操作達成するためにどのように
CASロックは何を?これらの問題を引き起こします

揮発性のアプリケーション

マルチスレッド揮発性軽量の同期、同期され、揮発性の演劇に重要な役割をプログラミングでは、マルチプロセッサの開発における共有変数の「可視性」を保証します。アトムの可視性。ジャストフォーカス)がスレッドコンテキストの切り替えやスケジューリングを起こさないため、同期の実行および使用のコストよりも低くなっています。この理解は、コンテキストスイッチが発生します逆波が同期され、synchronizedキーワードの使用は、リソースの競合を結果のコンテキストスイッチを引き起こしては。と言うことは本当にそう?正確であるこの記事では、ハードウェアレベルでの詳細な分析となります)実現は、揮発性どのようにIntelプロセッサです。

揮発性の原則の定義と実装

揮発性のJava言語仕様バージョン3の定義は、以下:Javaプログラミング言語だけでは、この変数を介して取得する排他ロックを保証しなければならないアクセスへのスレッドが共有変数を確保するために、変数を共有することができます正確かつ一貫してスレッドを更新することができます。Java言語は、揮発性の提供、およびいくつかのケースではロックよりも便利であることを。フィールドがvolatileとして宣言されている場合、Javaのスレッドのメモリモデルは、すべてのスレッドがこの変数の値が同じであることを保証参照します。

のは、揮発性の2の原則の具体的な実装を説明しましょう。

プロセッサのキャッシュがメモリに書き戻される原因1)ロックが命令を接頭辞
2)プロセッサのキャッシュメモリは、他のプロセッサのキャッシュが無効です原因に書き戻されます。
インタビュアーは、揮発性の基礎となる実装についてあなたを尋ねた場合、あなたは関与の原則を明確にすることができれば、あなたは牛のペンプラスを飛んでいる、これら2つの非常にNiubiの結果を知ることができます

揮発性の使用の最適化

さて、このセクションでは、独自のカザフスタンで読むことができます興味のある学生、存在しないテストを終了するには、

同期の実装の原理と応用

同期を達成するために、同期の基礎を使用してください:Javaの各オブジェクトをロックとして使用することができます。以下の三つの形式で特定のパフォーマンス。

通常の同期方法のために、ロックオブジェクトの現在のインスタンスです。
静的な同期メソッドの場合、ロックは現在のクラスのClassオブジェクトです。
ブロックを同期化する方法は、オブジェクトのロックがSynchonizedブラケットを構成されています。
この場所を理解し、あなたはクラスが抽象オブジェクトである知っている必要があり、オブジェクトは、クラスのインスタンスであります

アクセス同期ブロックにスレッドの試みは、それが最初のロックを取得する必要がある場合、あなたが終了するか、例外をスローする場合、ロックが解除されなければなりません。だからここで最後にロックがありますか?どのような情報は、ロックその中に保存されていますか?

JVM仕様では、メソッドを実装するための入り口と出口モニターオブジェクトに基づいてJVM、JVMの同期およびブロック同期Synchonizedの原則の実現から見ることができますが、2の実装の詳細は同じではありません。ブロック同期がmonitorenterとmonitorexit命令を使用して達成され、同期化の方法は、別の方法を使用して実装され、JVM仕様で詳細に説明しない細部しかしながら、同じ方法は、これら2つの命令の同期化に使用することができます。
monitorenter命令が同期コードの開始位置にコンパイルされ、ブロック内に挿入され、monitorexitは、それぞれ対応するペアmonitorexitを有していなければならないことを確実にするための方法および例外、JVMのmonitorenterの端部に挿入されます。任意のオブジェクトは、それにモニタに関連しており、保持された後、モニタは、それがロックされています。monitorenter命令にスレッドの実行は、ロックオブジェクトを取得しようとしているモニターに対応するオブジェクトの所有権を取得しようとしたとき。

Javaオブジェクトヘッダ

ロックは、Javaオブジェクトの存在を事前に同期しています。被験体はワード幅のメモリ・オブジェクト・ヘッダ2と、非配列型である場合、オブジェクトは、配列型、三つの言葉広い(ワード)の記憶オブジェクトヘッダを持つ仮想マシンである場合。32ビット仮想マシンを、以下に示すように、4バイト、すなわち32ビットに等しい幅ワードで。

ここに画像を挿入説明
マーク・ワードは、先のJavaのデフォルトのストレージオブジェクトのハッシュコード、年齢や世代ロックフラグ内のオブジェクト。デフォルト・ストレージ構造に示すようにマークワード32は、JVMに従います。
ここに画像を挿入説明
動作中に、マーク・ワードに格納されたデータは、ロックフラグに応じて変化します。以下に示すようにマークWordは、以下の4つのデータストアに変更してもよいです。
ここに画像を挿入説明
図に示すように、64ビットの仮想マシンでは、マークWordは、64ビットサイズ、ストレージ構造です。
ここに画像を挿入説明アドレスにこの知識は、私はあなたが宿題を残して与えることができます。Integerオブジェクトの合計メモリサイズ?この1は私がいつも根底にある開発者の理解を調べるために面接の対象となります。ああインタビューテストサイト

锁的升级与对比

在 Java SE 1.6中,锁一共有4种状态,级别从低到高依次是:无锁状态、偏向锁状态、轻量级锁状态和重量级锁状态,这几个状态会随着竞争情况逐渐升级。锁可以升级但不能降级。这种锁升级却不能降级的策略,目的是为了提高获得锁和释放锁的效率,下文会详细分析。

偏向锁

HotSpot[1]的作者经过研究发现,大多数情况下,锁不仅不存在多线程竞争,而且总是由同一线程多次获得,为了让线程获得锁的代价更低而引入了偏向锁。

(1)偏向锁的撤销
ここに画像を挿入説明
(2)关闭偏向锁

偏向锁在Java 6和Java 7里是默认启用的,但是它在应用程序启动几秒钟之后才激活,如有必要可以使用JVM参数来关闭延迟:-XX:BiasedLockingStartupDelay=0。如果你确定应用程序里所有的锁通常情况下处于竞争状态,可以通过JVM参数关闭偏向锁:-XX:-
UseBiasedLocking=false,那么程序默认会进入轻量级锁状态。

轻量级锁
(1)轻量级锁加锁

线程在执行同步块之前,JVM会先在当前线程的栈桢中创建用于存储锁记录的空间,并 将对象头中的Mark Word复制到锁记录中,官方称为Displaced Mark Word。然后线程尝试使用 CAS将对象头中的Mark Word替换为指向锁记录的指针。如果成功,当前线程获得锁,如果失 败,表示其他线程竞争锁,当前线程便尝试使用自旋来获取锁。

(2)轻量级锁解锁

轻量级解锁时,会使用原子的CAS操作将Displaced Mark Word替换回到对象头,如果成 功,则表示没有竞争发生。如果失败,表示当前锁存在竞争,锁就会膨胀成重量级锁。图2-2是 两个线程同时争夺锁,导致锁膨胀的流程图。
ここに画像を挿入説明

因为自旋会消耗CPU,为了避免无用的自旋(比如获得锁的线程被阻塞住了),一旦锁升级 成重量级锁,就不会再恢复到轻量级锁状态。当锁处于这个状态下,其他线程试图获取锁时, 都会被阻塞住,当持有锁的线程释放锁之后会唤醒这些线程,被唤醒的线程就会进行新一轮的夺锁之争。

锁的优缺点对比
ここに画像を挿入説明
下面这张图能够吃透,就可以出师了
ここに画像を挿入説明

原子操作的实现原理

原子(atomic)本意是“不能被进一步分割的最小粒子”,而原子操作(atomic operation)意 为“不可被中断的一个或一系列操作”。

术语定义

处理器如何实现原子操作
这两个知识点有兴趣的同学一样可以自行阅读哈,下节课抽问回答

Java如何实现原子操作

在Java中可以通过锁和循环CAS的方式来实现原子操作。
(1)使用循环CAS实现原子操作

JVM中的CAS操作正是利用了处理器提供的CMPXCHG指令实现的。自旋CAS实现的基本 思路就是循环进行CAS操作直到成功为止。

从Java 1.5开始,JDK的并发包里提供了一些类来支持原子操作,如AtomicBoolean(用原子方式更新的boolean值)、AtomicInteger(用原子方式更新的int值)和AtomicLong(用原子方式更新的long值)。这些原子包装类还提供了有用的工具方法,比如以原子的方式将当前值自增1和自减1。

(2)CAS实现原子操作的三大问题

1)ABA问题。

因为CAS需要在操作值的时候,检查值有没有发生变化,如果没有发生变化则更新,但是如果一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它 的值没有发生变化,但是实际上却变化了。ABA问题的解决思路就是使用版本号。在变量前面追加上版本号,每次变量更新的时候把版本号加1,那么A→B→A就会变成1A→2B→3A。从 Java 1.5开始,JDK的Atomic包里提供了一个类AtomicStampedReference来解决ABA问题。这个 类的compareAndSet方法的作用是首先检查当前引用是否等于预期引用,并且检查当前标志是否等于预期标志,如果全部相等,则以原子方式将该引用和该标志的值设置为给定的更新值。

   	/**
     * Atomically sets the value of both the reference and stamp
     * to the given update values if the
     * current reference is {@code ==} to the expected reference
     * and the current stamp is equal to the expected stamp.
     *
     * @param expectedReference the expected value of the reference
     * @param newReference the new value for the reference
     * @param expectedStamp the expected value of the stamp
     * @param newStamp the new value for the stamp
     * @return {@code true} if successful
     */
    public boolean compareAndSet(V   expectedReference,
                                 V   newReference,
                                 int expectedStamp,
                                 int newStamp) {
        Pair<V> current = pair;
        return
            expectedReference == current.reference &&
            expectedStamp == current.stamp &&
            ((newReference == current.reference &&
              newStamp == current.stamp) ||
             casPair(current, Pair.of(newReference, newStamp)));
    }
V expectedReference, // 预期引用
V newReference, // 更新后的引用
int expectedStamp, // 预期标志
int newStamp // 更新后的标志

2)循环时间长开销大。

自旋CAS如果长时间不成功,会给CPU带来非常大的执行开销。如果JVM能支持处理器提供的pause指令,那么效率会有一定的提升。pause指令有两个作用:第 一,它可以延迟流水线执行指令(de-pipeline),使CPU不会消耗过多的执行资源,延迟的时间 取决于具体实现的版本,在一些处理器上延迟时间是零;第二,它可以避免在退出循环的时候 因内存顺序冲突(Memory OrderViolation)而引起CPU流水线被清空(CPU Pipeline Flush),从而 提高CPU的执行效率。

3)只能保证一个共享变量的原子操作。

当对一个共享变量执行操作时,我们可以使用循 环CAS的方式来保证原子操作,但是对多个共享变量操作时,循环CAS就无法保证操作的原子性,这个时候就可以用锁。还有一个取巧的办法,就是把多个共享变量合并成一个共享变量来操作。比如,有两个共享变量i=2,j=a,合并一下ij=2a,然后用CAS来操作ij。从Java 1.5开始,JDK提供了AtomicReference类来保证引用对象之间的原子性,就可以把多个变量放在一个对象里来进行CAS操作。

(3)使用锁机制实现原子操作

そのロックを操作できるようにするロックを獲得するスレッドの専用メモリ領域のロック機構を確実にします。ロック機構、バイアスされたロック、ロック及び軽量ミューテックスの様々なJVMの内部。興味深いことである、それはサイクリングCASはロックを解除するときに使用されるシンクブロックを終了すると、ロックを取得するためにループCASの方法を使用している場合、スレッドが同期ブロックを入力したいときにバイアスされ、ロックに加えて、JVMは、ロックの方法がある使用済みのサイクルCAS、ある達成します。

概要

この章では、原則として、同期、揮発性とアトミックオペレーションの実現を一緒に勉強しています。ほとんどのJavaコンテナやフレームが実現し、この章で説明した揮発性とアトミック動作原理に依存しています。
ソースコードはGitHubでアドレスカウンタ:

https://github.com/PandaProgramApe/ape-current

一見、習慣を賞賛します。ようこそパンダプログラム歩行猿、次のさよなら

注意
条継続的に更新され、マイクロチャンネルサーチ「パンダプログラムAPE」は、より促すために初めてできます
いいえ公共ありません

公開された18元の記事 ウォン称賛20 ビュー80000 +

おすすめ

転載: blog.csdn.net/qq_35764295/article/details/103996541