blog

JUC 同時実行ツールクラスの詳細

スレッドプールの実行ルールをより明確にし、リソース不足のリスクを回避できるため、手動作成の方が優れています。一方、自動的に作成されたスレッドプールは、業務に十分に適合しない可能性があります。 CPU集...

Jan 13, 2021 · 21 min. read
シェア

1.同時実行安全性:相互排他的同期、非相互排他的同期、同期スキームなし

2.スレッドの管理と効率化

3.スレッド・コラボレーション

問題1:スレッド・プール

スレッドプールを使用する理由

問題1:スレッドの繰り返し生成はオーバーヘッドが大きい

問題2:多すぎるスレッドによるメモリの占有

少ないスレッド数を使用 - 過度のメモリ使用を回避

これらすべてのスレッドが動作し続け、繰り返しタスクを実行することができます。

  • レスポンスの高速化

  • CPUとメモリの合理的な使用

  • 統一管理

スレッドプールの作成と破棄

corePoolSizeはコア・スレッドの数を指します。スレッド・プールの初期化が完了した後、デフォルトではプール内にスレッドはなく、プールはタスクが到着するのを待ってから、タスクを実行する新しいスレッドを作成します。

スレッドプールでは、コアのスレッド数に加えてさらにスレッドを追加することが可能ですが、追加できるスレッド数には上限があり、それがmaxPoolSizeです。

スレッドプールは手動で作成すべきか、自動で作成すべきか

スレッドプールを実行するためのルールをより明確にし、リソースが不足するリスクを回避できるため、手動作成の方が優れています。一方、自動的に作成されたスレッドプールは、ビジネスに十分に適合しない可能性があります。

自動的に作成されます:

スレッドプールに設定する適切なスレッド数は?

CPU集約型:最適なスレッド数はCPUコア数の約1~2倍。

スレッド数=CPUコア数*です。

スレッドプールの停止

シャットダウン 停止開始

isShutdown isShutdown

isTerminated 完全に停止するかどうか

waitTermination 停止するかどうか一定時間待ちます。

shutdownNowは即座に停止し、未完了のタスクを保存するための戻り値を持つことができます。

スレッドプールのタスク拒否

エクゼキュータが閉じられると、新しいタスクの投入は拒否されます。

また、エクゼキュータがスレッドとワークキューの最大容量に有限の境界を使用し、飽和した場合

  • ThreadPoolExecutor.AbortPolicy : タスクを破棄し、RejectedExecutionException をスローします。

    これはスレッド・プールのデフォルトの拒否ポリシーで、タスクが投入できなくなったときに例外をスローし、プログラムの実行状況をタイムリーにフィードバックします。ビジネスがクリティカルな場合、この拒否ポリシーを使用することが推奨されます。これにより、システムがこれ以上の同時実行を実行できない場合、例外によって時間内にそれを検出することができます。

  • ThreadPoolExecutor.DiscardPolicy: タスクを破棄しますが、例外はスローしません。

    このポリシーを使用すると、システムの異常な状態を検出できなくなる可能性があります。このポリシーは、重要でない操作に使用することをお勧めします。

  • ThreadPoolExecutor.DiscardOldestPolicy:キューの一番上のタスクを破棄し、拒否されたタスクを再送信します。

    この否定戦略は新旧の否定戦略です。この否定戦略を採用するかどうかは、実際の業務が古い仕事を捨てることを許容するかどうかとの天秤にかけ、慎重に判断する必要があります。

  • ThreadPoolExecutor.CallerRunsPolicy: タスクは呼び出し元スレッドによって処理されます。

    一般的に、失敗が許されず、性能要件が高くなく、同時実行性が小さいシナリオで使用されます。一般的に、スレッドプールは閉じられないため、つまり、投入されたタスクは必ず実行されますが、呼び出し元のスレッド自体によって実行されるため、タスクが複数回投入されると、後続のタスク実行がブロックされ、性能と効率は当然遅くなります。

スレッドプールの状態

問題2:Threadローカル

シナリオ

典型的なシナリオ 1: 各スレッドが排他オブジェクトを必要とする場合

典型的なシナリオ2:グローバル変数を各スレッド内に保存する必要があり、パラメータ受け渡しの手間を省くために、異なるメソッドで直接使用することができます。

共有オブジェクトの生成タイミングに応じて、initialValueまたはsetのいずれかを選択してオブジェクトを保存します。

つの役割

スレッド間で使用する必要があるオブジェクトの分離

オブジェクトはどのメソッドでも簡単に取り出すことができます!

利点

スレッドセーフの実現

ロック不要で実行効率向上

メモリをより効率的に使用し、オーバーヘッドを節約

リファレンスを渡す必要がなくなります。

ソースコードの解釈

注意点

メモリリーク

ThreadLocalMapの各Entryはキーへの弱い参照であり、同時に各Entryは値への強い参照を含んでいます。

JDKはこの点を考慮し、set、remove、rehashの各メソッドでNULLキーを持つEntryをスキャンし、対応する値をNULLに設定することで、値オブジェクトを取り戻すことができます。

ヌルポインタ例外

getメソッドが事前に設定または初期化されていない場合、getはnullとなり、オートボックス時や列車から呼び出されたときにnpeとなることに注意してください。

無理は禁物です。

ThreadLocalを使わなくても解決できる問題であれば、無理にThreadLocalを使う必要はありません。 例えば、タスク数が少ない場合、ローカル変数に新しいオブジェクトを作成すれば解決できる問題であれば、ThreadLocalを使う必要はありません。

問題3:ロック

なぜロックが必要なのですか?

1) 非効率:ロック解放が少ない、ロック取得時にタイムアウトを設定できない、ロック取得中のスレッドに割り込めない

2) 柔軟性に欠ける:ロックの追加と解放のタイミングが1つで、各ロックの条件が1つだけでは不十分な場合があります。

3) ロックの取得に成功したかどうかを知る方法がありません。

Lockの4つの方法があります。

プログラミングのアイデア:ロックはsynchronizedのように例外発生時に自動的に解放されるわけではないので、finallyで解放されます。

  • 一旦デッドロックに陥ると、lock()は永遠に待ち続けることになります。

  • tryLockタイムアウトで中止

  • lockInterruptiblyはタイムアウトをinfiniteに設定します。ロックを待っている間、スレッドは割り込まれる可能性があります。

  • unlock(): アンロック

ロックの分類

楽観的ロック --> 悲観的ロック

悲観的ロック - 相互排他的同期ロック

短所

ブロッキングとウェイクアップによるパフォーマンスの低下

恒久的なブロッキング:ロックを保持しているスレッドが恒久的にブロックされた場合、例えば、ノー・クワイト・ループやデッドロックなどのアクティビティ上の問題に遭遇した場合、そのスレッドがロックを解放するのを待っている惨めなスレッドは決して実行されません。

優先順位を反転

実例

Java での悲観的ロックの実装は、synchronized クラスと Lock 関連クラス、axure?

利用シーン

悲観的なロック:多くの同時書き込みの場合に適しており、より長い時間のロックを保持するクリティカルゾーンに適用され、悲観的なロックは、無駄なスピンと他の消費、典型的なケースの大量を避けることができます:

  • クリティカル・エリアにはIOオペレーションがあります
  • 2 クリティカルな市外局番が複雑、またはループが多い
  • 3 重要な地域は競争が激しい

楽観的ロック - 互いに排他的でない同期ロック

楽観的ロックは一般的にCASアルゴリズムを使って実装されます。

楽観的ロックの典型的な例としては、アトミック・クラス、並行コンテナなどがあります。

Git は楽観的ロックの典型的な例です。 リモートリポジトリにプッシュするとき、git はリモートリポジトリのバージョンが現在のバージョンより進んでいるかどうかをチェックします。 リモートリポジトリのバージョン番号がローカルリポジトリのバージョン番号と同じでない場合は、リモートリポジトリのコードを変更した他の人がいることを意味し、コミットは失敗します。リモートリポジトリのバージョン番号がローカルリポジトリのバージョン番号と同じ場合は、問題なくリモートリポジトリにコミットすることができます。

利用シーン

同時書き込みが少なく、ほとんどが読み取りであるようなシナリオに最適で、アンロックすることで読み取り性能に大きな差が出ます。

再入可能ロック - 再入可能でないロック

ReentrantLock,synchronized

getHoldCount():何回ロックを取得したか

isHeldByCurrentThread は、ロックが現在のスレッドによって保持されているかどうかを示します。

getQueuelLengthは、現在のキューに返すことができますどのくらいロックを待っている、一般的にこれらの2つのメソッドは、開発および使用するデバッグ時間、あまり行の使用後です。

デッドロックをある程度防止

公平なロック - 不公平なロック

定義と設計目的

公平性とは、スレッドから要求された順番にロックを割り当てることです;

非フェアとは、リクエストの順番がリクエストされた順番通りにならないことを意味し、特定の状況下ではキュージャンプが可能です。

Javaの設計者は、効率を改善し、ウェイクアップによるギャップを避けるために、このように設計しました。

// 
private Lock queueLock = new ReentrantLock(false);

tryLock に関する注意

tryLock()メソッドは公平性のルールに従わず、スレッドがtryLockを実行した場合、あるスレッドがロックを解放すると、他のスレッドがキューで待機していても、ロックしようとしているスレッドがロックを取得することができます。

利点と欠点の比較

ソースコード解析

共有ロック - 排他ロック

定義

排他的ロックは、排他的ロック、排他的ロックとしても知られています。

共有ロックはリードロックとも呼ばれ、共有ロックを取得した後、閲覧は可能ですが、変更や削除はできません。

共有ロックと排他ロックの典型は、読み取り/書き込みロックのReentrantReadWriteLockで、読み取りロックは共有ロック、書き込みロックは排他ロックです。

読み取りと書き込みのロック規則

もっと読むか、書くか。

キューイング戦略

エクイタブルロック

不正ロック

書き込みロックはいつでも挿入可能

読み取りロックが挿入できるのは、キューの先頭で待機しているスレッドが、書き込みロックを取得しようとしているスレッドでない場合のみです。

ロックの上げ下げ

ロックのダウングレードはサポートされていますが、アップグレードはサポートされていません。

スピンロック --> ブロッキングロック

定義

これは、スレッドがロックを取得するときに、そのロックがすでに他のスレッドによって取得されている場合、そのスレッドはループ内で待機し、ロックが正常に取得できるかどうかを判断し続け、ロックが取得されるまでループを終了しないということです。--スピンロック

ブロッキング・ロックはスピン・ロックの逆で、ロックがない状況に遭遇した場合、スレッドが起動するまでブロックします。

欠点

ロックを取得したスレッドは常にアクティブですが、有効なタスクは実行しません。

実例

AtomicIntegerの実装:スピンロックの実装の原則は、CASは、AtomicIntegerの呼び出しは、Do-whileループのソースコード内の自己インクリメント操作のための安全でないスピン操作である場合は、他のスレッドの競争の過程で発生した修正プロセスは、成功の修正まで、デッドループの中で、失敗の修正につながった!

利用シーン

スピンロックは一般的にマルチコアサーバで使用され、同時実行性が特に高くない場合はブロッキングロックよりも効率的です。

スピンロックは、クリティカルゾーンが比較的短い場合に適しています。

割り込み可能なロック

ロックの最適化

ジェイ・ブイ・エム

スピンロックとアダプティブ

ロックのブロックに何回リトライしますか?

ロックの排除

ロックする必要のない部分の分析

ロックの粗密化

隣接するコードは複数回加算され、解除されます。

関係者

同期コード・ブロックの縮小

メソッドをロックしないようにします。

ロックリクエスト数の削減

ロックをロックに含めないようにしましょう。

質問4:アトミッククラス

利点

より細かい粒度:アトミック変数は、競合の範囲を変数レベルまで縮小します。これは、利用可能な最も細かい粒度であり、ロックは通常、アトミック変数よりも細かい粒度です。

より効率的:一般的に、アトミッククラスの使用はロックの使用よりも効率的です。

AtomicIntegerよく使用されるメソッド

public final int get//現在の値を取得し、新しい値を設定する
public final int getAndIncrement//現在値を取得し、自己減少させる
public final int getAndAdd//現在値を取得し、期待値を追加する

Atomic*Reference参照型アトミッククラス

整数が原子性を保証するのに対して、AtomicReference はオブジェクトが原子性を保証できます。もちろん、AtomicReference は AtomicInteger よりも強力です。使い方は AtomicInteger に似ています。

AtomicIntegerFieldUpdater は、通常の変数をアップグレードします。

使用例:アトミックなget-set操作が必要になることがあります。

注目点

リフレクションは一番下で使用され、プライベートとスタティック・プロパティをアップグレードすることはできません。

Adder

は、Java 8では、比較的新しいクラス、高い同時実行LongAdder AtomicLongの高効率よりも導入されますが、時間のためのスペースの本質は、競争が激しい場合、LongAdderは、競合の確率を減少させる変更のための別のCellに対応する別のスレッドに、マルチセグメントのロックの概念は、同時実行性を向上させます。

LongAdderの改良

LongAdderでは、各スレッドは独自のカウンタを持ちます。このカウンタは、他のスレッドのカウンタと干渉しないように、自身のスレッド内でのカウントにのみ使用されます。

LongAdder は、内部ベース変数とカウントに関与する Cell の配列を持つ、セグメ ントされた累積の概念を導入しています。

BASE変数:競争は激しくなく、この変数に直接帰属

セル配列:個々のスレッドが自分のスロットに蓄積されるように広がっていく競争的なもの Cell[i].

LongAdderは、2つの重要なメソッドがあります:加算と和は、加算は、スレッドセーフな加算であり、和は、戻り値であり、マルチスレッドの同時更新は、競合を減らすために、実行する別の変数にハッシュ化されるので、最終的な戻り値は、これらの変数の合計を取得することです。あなたは正確な戻り値を取得したい場合、またはAtomicLongを使用する必要がありますので、この点を介してまた、それは唯一の統計的なシナリオに適用され、正確ではありません結果を得るために合計を見ることができる、パフォーマンスと精度の両方することはできません。

Accumulator

並列コンピューティング

CAS

定義

CASは3つのオペランドを持ちます:メモリ値V、期待値A、および修正される値Bです。最後に現在値 V

アプリケーション・シナリオ

オプティミスト・ロック

コンカレントコンテナ

Atomic::AtomicIntegerは、メモリ内のデータを直接操作するためのUnsafeツールと、UnsafeクラスのcompareAndSwapIntメソッドをロードします。アトミックな比較と置換はAtomic::cmpxchgによって実現され、パラメータxは更新されようとしている値、パラメータeは元のメモリ内の値です。この時点で、CASの全プロセスが最終的に完了します。

デメリット

ABAの問題

過度のスピン時間

final

オブジェクトは、作成後にその状態を変更できない場合はイミュータブルであり、イミュータブル・オブジェクトはスレッドセーフです。

クラスは継承から保護され、メソッドはオーバーライドから保護され、変数は変更から保護されます。

final修飾変数

意味:finalによって変更された変数は、その値を変更できないことを意味します。変数がオブジェクトの場合、オブジェクトへの参照は変更できませんが、オブジェクト自体の内容は変更できます。

  • クラス内の最終属性:1.等号の右への直接割り当て、2.コンストラクタ割り当て、3.初期ブロック割り当て
  • クラスの静的最終属性:1.等号の右への直接割り当て、2.静的初期コードブロック割り当て
  • メソッド内の最終変数:代入タイミングは指定しませんが、使用前に代入を指定します。

final修正方法

コンストラクタのメソッドでは final 修飾子を使用できません。

オーバーライドすることはできません、つまり、オーバーライドすることはできません、たとえサブクラスがメソッドの同じ名前を持っていても、それはオーバーライドされません、これは静的メソッドが同じことです。

final

継承不可 - 文字列

不変

基本的なデータ型の場合、finalによって変更されても不変であることは確かですが、オブジェクト型の場合は、オブジェクトの状態が決して変化しないことが保証されていなければなりません。

  • 一度オブジェクトが作成されると、その状態を変更することはできません。
  • すべてのプロパティは最終的に変更されます。
  • オブジェクト作成時のエスケープなし

スタック閉鎖

メソッドで作成された新しいローカル変数は、実際には各スレッドのプライベートスタック空間に格納され、各スタックのスタック空間は他のスレッドからアクセスできないので、スレッドセーフの問題はありません。これが有名な「スタック閉鎖」テクニックで、「スレッド閉鎖」テクニックの一例です。

tips

問題5:同時実行コンテナ

コンカレント機能は、ほとんどがCASによる同時実行です。

CopyOnWriteは、元のデータのコピーを作成することでこれを行います。

ブロッキングはAQSで実施

概要

ConcurrentHashMap: スレッドセーフなハッシュマップ

CopyOnWriteArrayList: 読み込みが多く書き込みが少ない場合のスレッドセーフなリスト。

BlockingQueue: これはブロッキングキューを表すインターフェースで、データ共有のためのチャネルとして使用するのに理想的です。

ConcurrentLinkedQueue:リンクリストを使用して実装された効率的なノンブロッキング並行キュー。スレッドセーフなLinkedListと見なすことができます。

ConcurrentSkipListMap: スキップテーブルのデータ構造を使用して高速検索を行うMapです。

ConcurrentHashMap

なぜHashMapはスレッドセーフではないのですか?

データ消失につながる同時プット衝突

プットの同時拡張はデータ損失につながります

デッドループによるCPU 100%: 複数のスレッドが同時に拡張している場合、循環チェーンテーブルが発生し、CPU 100% になることがあります。

ConcurrentHashMap1.7

ConcurrentHashMap1.8

相違点のまとめ

1.データ構造

コンカレンシー16より「各ノードは互いに独立しています。

2. ハッシュによる紛争解決

Zipより---「Zip+Red&Black

3.同時実行セキュリティの確保

セグメンテッド・ロックより「CAS+同期化

4.クエリーの複雑さ

つのメソッド putVal+get

ConcurrentHashMap の誤った使用

操作の組み合わせはスレッドセーフではありません --- replace メソッドか putIfAbsent を使ってください。

CopyOnWriteArrayList

より多く読み、より少なく書く:ブラックリスト、毎日更新、リスナー:反復操作、冗長な修正操作

読み書きルール

読み込みは完全にロックフリーで、書き込みは読み込み操作をブロックしません。書き込みだけが

イテレータ内のリストの変更

  • ArrayList
  • CopyOnWriteArrayList はエラーを報告しません。

デメリット

データの一貫性の問題:CopyOnWrite コンテナが保証できるのは、データの最終的な一貫性だけであり、データのリアルタイムの一貫性は保証できません。そのため、書き込まれたデータをすぐに読めるようにしたい場合は、CopyOnWrite コンテナを使用しないでください。

メモリ使用量の問題:CopyOnWriteの書き込みはコピーメカニズムであるため、書き込み操作が実行されると、2つのオブジェクトが同時にメモリに存在することになります。

同時実行キュー

ブロックキュー

主なメソッド

  • 置く、取る

    takeメソッド:キューを取得し、キューの先頭ノードを削除し、一度takeの実行は、キューにデータがない場合は、キューにデータがあるまでブロック putメソッド:要素を挿入します。しかし、キューがいっぱいの場合、それは挿入を続行することはできません、それはキューに空き領域があるまでブロックされます。

  • 追加、削除、要素

    add: 入れて、一杯になったら例外をスローします。

    remove: 削除、空の場合は例外をスローします。

    element: ヘッダ要素を返します。空の場合は例外をスローします。

  • オファー、投票、覗き見

    offer: 入れて、満杯ならfalseを返します。

    poll: 取り出して削除、空はnullを返します。

    peek: 取り出す、空 return null

ArrayBlockingQueue

  • 境界があり、作成には容量を指定する必要があります。
  • 公平かどうかを指定できます。

LinkedBlockingQueue

  • 無境界
  • テイクとプットは2つのロックを使用します。

PriorityBlockingQueue

  • サポート優先度
  • 拡張可能 - 「境界のないキュー
  • PriorityQueueのスレッドファースト版

SynchronousQueue

  • 容量が0であるため、直接受け渡しに使用するには優れた同時データ構造です。

DelayQueue

  • 遅延キュー、遅延時間順
  • 要素はDelayedインターフェイスを実装する必要があります。

ノンブロッキング・キュー

ConcurrentLinkedQueue

ノンブロッキングキューのみConcurrentLinkedQueueこの種の並行処理パッケージは、名前が意味するようにConcurrentLinkedQueueは、そのデータ構造として連鎖リストの使用は、CASのノンブロッキングアルゴリズムの使用は、スレッドセーフを達成するために、より高いシナリオのパフォーマンス要件の並行処理での使用に適しています。高い性能が要求される同時実行シナリオでの使用に適しています。

選択

  • 境界線 - 「入れなければならないものはどれくらいありますか?
  • スループット --> 一般的にLinkedBlockingQueue > ArrayBlockingQueue

課題6:並行プロセスの制御

概要

  • CountDownLatchカウントダウンラッチ
  • Semaphore
  • Condition
  • CyclicBarrierループフェンス

CountDownLatch

CountDownLatchは再利用できません。再カウントが必要な場合は、CyclicBarrierを使用するか、新しいCountDownLatchインスタンスを作成することを検討してください。

awaitを使って1回引きます。

Semaphore

セマフォは、限られた数のリソースの使用を制限または管理するために使用できます。セマフォが所有するライセンス数が0の場合、ライセンスを取得したい次のスレッドは、他のスレッドがライセンスを解放するまで待つ必要があります。Fairnessはセマフォの初期化時に設定することができ、一般的にはtrueに設定する方が理にかなっています。

Condition

実際、Lockがsynchronizedの代わりに使われるなら、Conditionは対応するObject.wait/notifyの代わりに使われます。awaitメソッドでは、最初に自分で手動でロックを解除する必要はありません。waitを呼び出す場合は、ロックを保持する必要があります、そうでない場合は例外がスローされます、Object.waitと同じです。

ロックは複数のロック・オブジェクトを生成することができ、await()とsignal()を併用することで、より細かく処理を制御することができます。

 private Lock lock = new ReentrantLock();
 private Condition notFull = lock.newCondition();
 private Condition notEmpty = lock.newCondition();

CyclicBarrierループフェンス

//5つすべてが立ち上がったとき、何を始めるか?
CyclicBarrier cyclicBarrier = new CyclicBarrier(5, new Runnable() {
 @Override
 public void run() {
 System.out.println("みんな揃った!みんなで一斉に行こう!");
 }
 });

つまり、CountDownLatchはイベントに使用され、CyclicBarrierはスレッドに使用されます。

再利用性は異なります。CountDownLatchは、0までカウントダウンしてラッチを開くトリガをかけた後、新しいインスタンスが作成されない限り、再び使用することはできません。

質問7:AQS

AQSを使用する理由

AQSはロック、シンクロナイザー、コラボレーションツールクラスを構築するためのツールクラスです。AQSを使えば、より多くのコラボレーションツールキットを簡単に書くことができます。

ReentrantLockとSemaphoreは、上記のコラボレーションクラスが類似しているため、ツールクラスを抽出することができれば、それを直接使用することができ、多くの詳細から保護することができますので、その上に独自の "ビジネスロジック "にのみ焦点を当てています!

内部的には、AQS を継承した Sync クラスがあります。

原理説明

AQSの核となるのは、主に3つのセクションです:

  • state
  • スレッドロックを制御するためのFIFOキュー。
  • 連携ツールに期待される重要な獲得/解放方法

アプリケーション

質問8:FutureとCallable

Runnable

戻り値を返せない

チェックされた例外を投げることもできません。

Callable

Future

メソッドは時間がかかるので、サブスレッドを使用して実行できます。

  • get

Callableインターフェイスが返す実行結果を取得するには、Future.getを使用します。 getメソッドの動作はCallableタスクの状態に依存し、以下の5つのケースのみです:

1, タスクが正常に完了した場合: getメソッドはすぐに結果を返します。

2, タスクが完了していない: タスクが完了するまで、getはブロックされます。

3、タスクの実行プロセスは、Exceptionをスローします:getメソッドは、ExecutionExceptionをスローします:ここでスローされる例外は、呼び出しの実行中にスローされる例外の種類は何ですか、最後のgetメソッドは、ExecutionExceptionの例外の種類をスローされ、例外がスローされるに遭遇していないが、呼び出しのget時メソッドは、例外が発生したときではなく、getメソッドが呼び出されたときにスローされます。

4, タスクがキャンセルされた場合: getメソッドはCancellationExceptionをスローします。

5、タスクのタイムアウト:getメソッドは、オーバーロードされたメソッドを持って、遅延時間を渡され、時間が結果が得られていないに来ている場合、getメソッドは、TimeoutExceptionをスローします。

  • cancel

タスクの実行をキャンセルし、実行中のタスクを中断するかどうかを表すtrueとfalseの差を渡します。

Future.cancelが適用されます:

1.タスクは割り込みを処理できます

Future.cancelは、まだ開始されていないタスクの開始を回避するためにのみ使用され、適用されます:

1.割り込みタスク処理の失敗

2.タスクがキャンセルをサポートしているか不明

3 - すでに開始されているタスクの実行完了を待つ必要があります。

  • isDone()

タスクが正常に終了しなかった場合でも、タスクの実行が終了したかどうかを判断します。

  • isCancelled()

このタスクがキャンセルされたかどうかを判断する、限られた時間内にタスクの結果を得る、など。

使用メソッド

  • 使用法 1: スレッドプールの submit メソッドは Future オブジェクトを返します。

まず、スレッドプールにタスクを投入すると、スレッドプールはすぐに空のFutureコンテナに戻ります。スレッドのタスクが実行されると、つまり結果が得られると、スレッドプールはその結果を所定のFutureに流し込みます。

  • 使用法2:FutureTaskを使用してFutureを作成

FutureTaskは、CallableをFutureとRunnableに変換するラッパーです。

 Task task = new Task();//Callable
 FutureTask<Integer> integerFutureTask = new FutureTask<>(task);
 new Thread(integerFutureTask).start();
 Task task = new Task();
 FutureTask<Integer> integerFutureTask = new FutureTask<>(task);
 ExecutorService service = Executors.newCachedThreadPool();
 service.submit(integerFutureTask);

Futureの注意が必要です。

  • forループでfutureの結果を一括取得する場合、スレッドの一部が非常に遅くなりやすいので、getメソッド呼び出しはタイムアウト制限を使用するか、CompletableFutureツールクラスを使用する必要があります。
  • フューチャーのライフサイクルは後戻りできません。

課題9:キャッシングツールの反復使用

  1. hashMap
  2. synchronizedキャッシュ・メソッドのロック
  3. キャッシュをビジネスから切り離すためのデコレータの最適化
  4. 粒度を小さく→同期ロックコードブロック
  5. ConcurrentHashMap
  6. 重複計算が発生した場合、Futureを使用します。これは、getメソッドが初期に投入されたタスクがあるかどうかを確認するためです。
  7. また、getメソッドを呼び出して
  8. エラーは計算クラスで発生する可能性があり、getメソッドで発生する可能性のある3つの例外は異なる方法で処理されます。
  9. キャッシュ汚染、エラーのロールバックを考慮してください。タスクは空にできます。
  10. キャッシュの期限切れ関数を使用すると、ScheduledExecutorService のスレッドプールを使用して、時限遅延タスクを設定できます。
  11. 設定が同時に期限切れになるように設定されている場合、どの設定も同時にキャッシュを取得することができず、キャッシュ雪崩、キャッシュヒット、および高同時性下でのその他のキャッシュ問題を引き起こします。---> キャッシュ時間ランダム
  12. 高同時性テスト - 「統一制御にはCountDownLatchを使用し、スレッドごとの時間出力にはThreadLocalを使用します。
Read next

JWTについて

JWTの構造WTは、暗号化された文字の文字列です。文字列は、説明するために、次のケースを再順序で3つの部分に分割されます。

Jan 13, 2021 · 2 min read