CAS 8同時パフォーマンスを最適化する方法のJavaのJavaのインタビューの質問についての方言の話?

この記事はから再生されたノートのアーキテクチャフペルジン

まず、先行レビュー

 

みんなの記事は特に見、揮発性の原則をおしゃべり:「最後に、同時実行の揮発性のJavaインタビューの質問が何であるかについての話方言?"

 

この記事では、CAS操作のパフォーマンスを向上させ、最適化するために、どのように我々はCAS関連の下でJavaとの契約について話アトミック操作を与え、およびJava 8。

 

アトミックシリーズのような原子ので、両方の並行プログラミング、JDKのソースコード、またはオープンソースプロジェクトの様々な、しばしば使用されています。そして、Javaの同時インタビューで、この1はまた、比較的高い周波数のテストサイトですので、誰もがチャットするために、それはまだ価値があります。

 

 

第二に、シーンの導入、問題のハイライト

 

まあ、我々が開始します!複数のスレッドを仮定し、例えば、次のコードを可変絞りを蓄積する必要があります。 

 

 

 

実際には、直接データ変数にこのような同時複数のスレッドを変更するため、コードの先頭部分が、OKでない、スレッド安全でない性的行動、データ値の変化にリードが変化することが期待値に適合しません。

 

例えば、データ++の操作を実行するために、それぞれのデータを20個のスレッドを言って、我々は最終データの値が20を向けるだろう、それはないと信じています。

 

最後の可能な値のデータが18、または19であり、次のマルチスレッド動作可能であるため、不正確なデータにつながるが、このようなセキュリティ上の問題です。

 

なぜ正確にしないために?この資料に記載されていない範囲、これは限り学生は、Javaを学んだとして、一般的なので、確かにあまりにも多くのスレッドの同時実行の問題を認識しています。

 

 

第三に、最初の溶液:同期

 

だから、上記のコードのために、我々は一般的な方法をロックすることにより、彼はスレッドセーフになってみましょう、外観を変えていきます。

 

 

 

我々が追加したので、今回は、コードは、スレッドセーフである同期をインクリメント()メソッドを入力するために、各スレッドは1つのスレッドしかロックでき、同じ時間をロックしようとする前に、他のスレッドがロックを待機する必要が来るようにする、です。

 

このようにすることで、すべての時間が蓄積された変更データ1、データ障害の問題が発生しないようにすることができます。

 

古いルール!以下のチャートで見てみましょうが、同期ロックの下の効果や雰囲気を感じ、Nの同等は1つが、その値更新をキューに入れられたスレッド。

 

 

 

 

しかし、このような単純なデータ++の動作は、やり過ぎ、問題、少しやり過ぎを解決するため、マルチスレッド同期のヘビーロックに追加されます。

 

ジャワの更新バージョンを持つが、しかし、また、最適化の多くを行ったが、このプロセスは、単に業務を蓄積し、まだのように見える「重すぎる。」同期 人々は、より複雑なシーンと並行プログラミングの問題を解決するために同期させることができます。

 

また、このシナリオでは、あなたが使用している場合、各スレッドがまだ連載の等価ではないのでことを、同期?1本のライン、ロック、データ処理によって一つは、ロックを解除し、次に来ます。

 

 

 

第四に、より効率的なスキーム:アトミックその基本原理 - アトム

 

この単純なデータ++クラスの動作のために、実際には、我々は練習、Javaとの契約申し出に、以下のアトミックアトミッククラス、などのAtomicIntegerの範囲を変更することができます。

 

彼はマルチスレッドのセキュリティを保証することができた場合には、高性能な同時は値を更新します。次のコードで見てみましょう:

 

 

 

私たちは、上記のコードを見て、それは非常に簡単ではありません!複数のスレッドの同時実行が私のデータの値を与えるincrementAndGetのAtomicIntegerの()メソッド、意味が1つインクリメントされることができ、その後、最新の値の蓄積を返します。

 

このコードは、私がロックを見て、それを言うためにロックを解除しないでください!

 

実際には、ロック機構を備えた原子の原子基礎となるクラスは、伝統的な意味ではないが、CAS、CAS機構のないロック機構は、セキュリティの修正値を介してマルチスレッド確保しないように

 

CASそれは何ですか?彼のフルネームは次のとおりです。比較して設定あなたが設定する前に、それらを比較するためのものです。

 

いくつかの単語の男は最初のマップに、言いました!

 

 

 

それは次のようである彼らの根底にあるメカニズムののAtomicIntegerの値を変更するには、3つの同時実行スレッドを持っている場合我々は、上記のチャートを見て:

 

まず、第1の電流値を取得します各スレッドは、その後、他の人が中断されることはありません、これはアトミックCAS操作が完全に実行完了している必要がありますつまり、アトミックCAS操作を取ります。

 

然后CAS操作里,会比较一下说,唉!大兄弟!现在你的值是不是刚才我获取到的那个值啊?

 

如果是的话,bingo!说明没人改过这个值,那你给我设置成累加1之后的一个值好了!

 

同理,如果有人在执行CAS的时候,发现自己之前获取的值跟当前的值不一样,会导致CAS失败,失败之后,进入一个无限循环,再次获取值,接着执行CAS操作!

 

好!现在我们对照着上面的图,来看一下这整个过程:

 

  • 首先第一步,我们假设线程一咔嚓一下过来了,然后对AtomicInteger执行incrementAndGet()操作,他底层就会先获取AtomicInteger当前的值,这个值就是0。

     

  • 此时没有别的线程跟他抢!他也不管那么多,直接执行原子的CAS操作,问问人家说:兄弟,你现在值还是0吗?

     

  • 如果是,说明没人修改过啊!太好了,给我累加1,设置为1。于是AtomicInteger的值变为1!

     

  • 接着线程2和线程3同时跑了过来,因为底层不是基于锁机制,都是无锁化的CAS机制,所以他们俩可能会并发的同时执行incrementAndGet()操作。

     

  • 然后俩人都获取到了当前AtomicInteger的值,就是1

     

  • 接着线程2抢先一步发起了原子的CAS操作!注意,CAS是原子的,此时就他一个线程在执行!

     

  • 然后线程2问:兄弟,你现在值还是1吗?如果是,太好了,说明没人改过,我来改成2

     

  • 好了,此时AtomicInteger的值变为了2。关键点来了:现在线程3接着发起了CAS操作,但是他手上还是拿着之前获取到的那个1啊!

     

  • 线程3此时会问问说:兄弟,你现在值还是1吗?

     

  • 噩耗传来!!!这个时候的值是2啊!线程3哭泣了,他说,居然有人在这个期间改过值。算了,那我还是重新再获取一次值吧,于是获取到了最新的值,值为2。

     

  • 然后再次发起CAS操作,问问,现在值是2吗?是的!太好了,没人改,我抓紧改,此时AtomicInteger值变为3!

 

上述整个过程,就是所谓Atomic原子类的原理,没有基于加锁机制串行化,而是基于CAS机制:先获取一个值,然后发起CAS,比较这个值被人改过没?如果没有,就更改值!这个CAS是原子的,别人不会打断你!

 

通过这个机制,不需要加锁这么重量级的机制,也可以用轻量级的方式实现多个线程安全的并发的修改某个数值。

 

 

五、Java 8对CAS机制的优化

 

但是这个CAS有没有问题呢?肯定是有的。比如说大量的线程同时并发修改一个AtomicInteger,可能有很多线程会不停的自旋,进入一个无限重复的循环中。

 

这些线程不停地获取值,然后发起CAS操作,但是发现这个值被别人改过了,于是再次进入下一个循环,获取值,发起CAS操作又失败了,再次进入下一个循环。

 

在大量线程高并发更新AtomicInteger的时候,这种问题可能会比较明显,导致大量线程空循环,自旋转,性能和效率都不是特别好。

 

于是,当当当当,Java 8推出了一个新的类,LongAdder,他就是尝试使用分段CAS以及自动分段迁移的方式来大幅度提升多线程高并发执行CAS操作的性能!

 

 

 

在LongAdder的底层实现中,首先有一个base值,刚开始多线程来不停的累加数值,都是对base进行累加的,比如刚开始累加成了base = 5。

 

接着如果发现并发更新的线程数量过多,就会开始施行分段CAS的机制,也就是内部会搞一个Cell数组,每个数组是一个数值分段。

 

这时,让大量的线程分别去对不同Cell内部的value值进行CAS累加操作,这样就把CAS计算压力分散到了不同的Cell分段数值中了!

 

这样就可以大幅度的降低多线程并发更新同一个数值时出现的无限循环的问题,大幅度提升了多线程并发更新数值的性能和效率!

 

而且他内部实现了自动分段迁移的机制,也就是如果某个Cell的value执行CAS失败了,那么就会自动去找另外一个Cell分段内的value值进行CAS操作。

 

这样也解决了线程空旋转、自旋不停等待执行CAS操作的问题,让一个线程过来执行CAS时可以尽快的完成这个操作。

 

最后,如果你要从LongAdder中获取当前累加的总值,就会把base值和所有Cell分段数值加起来返回给你。

 

 

六、总结 & 思考

 

不知道大家有没有发现这种高并发访问下的分段处理机制,在很多地方都有类似的思想体现!因为高并发中的分段处理机制实际上是一个很常见和常用的并发优化手段。

おすすめ

転載: www.cnblogs.com/alimayun/p/12129809.html