1。ロングダー
Atomiclongと同様の方法で使用されていますが、Atomiclongよりも優れた性能を持っています。
LongdadderとAtomiclongはどちらもアトミック操作を使用してパフォーマンスを向上させます。ただし、LongadderはAtomiclongに基づいてホットスポット分離を実行します。ホットスポットの分離は、ロックされた動作のロック粒子サイズを縮小し、ロックをいくつかのロックに分離してパフォーマンスを向上させることに似ています。ロックフリーでは、同様の方法を使用してCASの成功率を高め、パフォーマンスを向上させることができます。
Longdadder回路図:
Atomiclongの実装方法は、内部に値変数があることです。複数のスレッドが自己障害で自己排除されている場合、それらはすべて、CASの指示を通じて機械命令レベルから操作され、同時性の原子性を確保します。 Atomiclongの効率を制限する唯一の理由は、高い並行性です。並行性が高いということは、CASの故障の可能性が高いこと、再試行時間が長く、スレッドが再試行するほど、CASの故障の可能性が高く、これが悪循環になり、Atomiclongの効率が低下することを意味します。
Longdadderは、値をいくつかのセルに分割し、すべてのセルを値に合わせます。したがって、Longdadderを追加および減算する場合、異なるセルで作動するだけです。異なるスレッドは、異なるセルでCAS操作を実行します。もちろん、CASの成功率は高くなっています(3+2+1 = 6、1つのスレッド3+1、もう1つのスレッド2+1、最後に8、Longadderには乗算と分割のAPIがありません)。
ただし、並行性数がそれほど高くない場合、いくつかのセルに分割するには、細胞と合計も維持する必要があります。これは、Atomiclongの実装ほど効率的ではありません。 Longadderは、この問題を解決するために賢い方法を使用しました。
最初の状況では、LongadderとAtomiclongは同じです。 CASが故障した場合にのみ、値はセルに分割されます。障害が発生するたびに、セルの数が増加します。これは、低い並行性でも効率的です。高い並行性では、この「適応」処理方法は、一定の数のセルに到達した後に失敗することはなく、効率は大幅に改善されます。
Longdadderは、時間のために空間を交換する戦略です。
2。CompleteFuture
完了ステージインターフェイス(40を超えるメソッド)を実装し、そのほとんどは機能プログラミングで使用されます。ストリーミングコールをサポートします
CompleteFutureはJava 8のFutureの拡張バージョンです
簡単な実装:
java.util.concurrent.completableFuture; public class askthread emblence runnable {completeablefuture <integer> re = null; public askthread(completeablefuture <integer> re){this.re = re; } @Override public void run(){int myre = 0; try {myre = re.get() * re.get(); } catch(例外e){} system.out.println(myre); } public static void main(string [] args)throws arturnedexception {final completeablefuture <integer> future = new CompleteableFuture <Integer>();新しいスレッド(new AskThread(Future))。start(); //長期の計算プロセススレッドをシミュレートする睡眠(1000); //完了の結果を通知してくださいfuture.complete(60); }}未来について最も批判されていることは、自分でタスクが完了したかどうかを待って確認する必要があるということです。将来、タスクが完了する時間は制御できません。 CompleteFutureの最大の改善点は、タスクの完了の時間も開いていることです。
future.complete(60);
完了時間を設定するために使用されます。
CompleteFutureの非同期実行:
public static integer calc(integer para){try {//長い実行スレッドをシミュレートする睡眠(1000); } catch(arturtedexception e){} para * paraを返します。 } public static void main(string [] args)throws arturnedexception、executionexception {final completeablefuture <integer> future = completablefuture .supplyasync(() - > calc(50)); System.out.println(future.get()); }完成可能なfutureのストリーミングコール:public static integer calc(integer para){try {//長い実行スレッドをシミュレートする睡眠(1000); } catch(arturtedexception e){} para * paraを返します。 } public static void main(string [] args)throws arturnedexception、executionexception {completeablefuture <void> fu = completablefuture .supplyasync(() - > calc(50))。 .thenaccept(system.out :: println); fu.get(); }複数の完了可能なフュータを組み合わせます:
public static integer calc(integer para){para / 2を返す; } public static void main(string [] args)throws arturnedexception、executionexception {completeablefuture <void> fu = completable future .supplyasync(() - > calc(50)).thencompose((i) - > completablefuture.supplyasync(() - > calc(i)) - str)。 "/" ").thenaccept(system.out :: println); fu.get(); }これらの例は、Java 8のいくつかの新機能にもっと焦点を当てています。ここに機能を説明するための例をいくつか紹介します。そのため、詳細に説明しません。
CompleteFutureはパフォーマンスとはほとんど関係ありませんが、機能的なプログラミングと機能の強化をサポートするためにより重要です。もちろん、完了時間の設定はハイライトです。
3。StampedLock
前の記事では、ロック分離が言及されたばかりで、ロック分離の重要な実装はreadwritelockです。 StampedLockは、readwriteLockの改善です。 StampedLockとReadWriteLockの違いは、StampedLockが読み取りをブロックすべきではないと考えていることであり、StampedLockは、読み取りと執筆が相互に排他的である場合、読み取りスレッドを書くことを許可しないではなく、読み取りを再読する必要があると考えています。このデザインは、より多くを読み、書くことを少なくするときに、スレッドの飢erを書くという問題を解決します。
したがって、StampedLockは、スレッドを書く傾向がある改善です。
StampedLockの例:
import java.util.concurrent.locks.stampedlock; public class point {private double x、y;プライベートファイナルスタンピードロックsl = new StampedLock(); void move(double deltax、double deltay){//排他的にロックされたメソッドlong stamp = sl.writelock(); {x += deltax; y += deltay; }最後に{sl.unlockwrite(stamp); }} double distancefromorigin(){//読み取り専用メソッドlong stamp = sl.tryoptimisticread(); double currentx = x、currenty = y; if(!sl.validate(stamp)){stamp = sl.readLock(); {currentX = x; currenty = y; }最後に{sl.unlockread(stamp); }} return math.sqrt(currentx * currentX + currenty * currenty); }}上記のコードは、ライティングスレッドと読み取りスレッドをシミュレートします。 StampedLockは、スタンプに従って相互に排他的かどうかを確認します。スタンプを一度書くと、特定の値が増加します。
tryoptimisticRead()
前述のように、読み書きが相互に排他的ではない状況です。
スレッドを読むたびに、最初に判断を下すでしょう
if(!sl.Validate(スタンプ))
検証では、最初にライティングスレッドの書き込みがあるかどうかを確認し、次に入力値が現在のスタンプと同じかどうか、つまり読み取りスレッドが最新のデータを読み取るかどうかを判断します。
ライティングスレッドの書き込みがある場合、またはスタンプ値が異なる場合、リターンは失敗します。
判断が失敗した場合、もちろん、繰り返し読んでみることができます。サンプルコードでは、繰り返し読み込もうとすることは許可されていませんが、代わりに楽観的ロックを使用して通常の読み取りロックに退化して読みます。この状況は悲観的な読書方法です。
Stamp = sl.readLock();
StampedLock実装のアイデア:
CLHスピンロック:ロックアプリケーションが失敗した場合、読み取りスレッドはすぐに吊り下げられません。ロックには、待機中のスレッドキューが維持されます。このキューには、ロックに適用されるが、成功したスレッドは記録されていないすべてのスレッド。各ノード(1つのノードがスレッドを表す)は、ロックビットを保存して、現在のスレッドがロックをリリースしたかどうかを判断します。スレッドがロックを取得しようとすると、現在の待機キューのテールノードが前身のノードとして取得されます。次のようなコードを使用して、プリアンブルノードがロックを正常にリリースしたかどうかを判断します
while(pred.locked){
}
このループは、前のノードがロックを放出するのを待つことで、現在のスレッドがオペレーティングシステムによって吊り下げられず、パフォーマンスが向上します。
もちろん、無限のスピンはありません。また、いくつかのスピンの後にスレッドは吊り下げられます。