同時処理


1. [必須] シングルトン オブジェクトの取得はスレッドの安全性を確保する必要があり、メソッドもスレッドの安全性を確保する必要があります。

注: リソース駆動クラス、ツール クラス、およびシングルトン ファクトリ クラスはすべて注意が必要です。

2. [必須] エラー発生時のバックトラッキングを容易にするために、スレッドまたはスレッド プールを作成するときに意味のあるスレッド名を指定してください。

肯定的な例:

public class TimerTaskThread extends Thread {
public TimerTaskThread(){
super.setName("TimerTaskThread"); ...
}

3. [必須] スレッド リソースはスレッド プールを通じて提供される必要があり、アプリケーションでのスレッドの明示的な作成は許可されません。

注: スレッド プールを使用する利点は、スレッドの作成と破棄にかかる時間とシステム リソースのオーバーヘッドを削減し、リソース不足の問題を解決できることです。スレッド プールを使用しない場合、システムが同様のスレッドを多数作成し、メモリ消費や 「過剰な切り替え」問題が発生する可能性があります。


4. [必須] スレッド プールは Executor を使用して作成することはできませんが、ThreadPoolExecutor を介して作成することはできます。この

処理方法により、学生は Make theスレッドプールの運用ルールがより明確になり、リソース枯渇のリスクが回避されます。

説明: Executor によって返されるスレッド プール オブジェクトの欠点は次のとおりです:

1)

FixedThreadPool および SingleThreadPool :

許可されるリクエスト キューの長さは Integer.MAX_VALUE です。これにより、大量のリクエストが蓄積され、OOM が発生する可能性があります。

2)

CachedThreadPool および ScheduledThreadPool:

作成できるスレッドの数は Integer.MAX_VALUE です。これにより、大量のスレッドが作成される可能性があります。スレッドが発生し、 OOM が発生します。


5. [必須] SimpleDateFormat はスレッドアンセーフなクラスです。通常、静的変数として定義すべきではありません。

static として定義されている場合、ロックするか、DateUtils ツールを使用する必要があります。

良い例: スレッドの安全性に注意し、DateUtils を使用します。次の処理も推奨されます:

private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>() {
@ Override
protected DateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd");
}
};

注: JDK 8 アプリケーションの場合は、Date の代わりに Instant、Calendar の代わりに LocalDateTime、Simpledateformatter の代わりに DateTimeFormatter を使用できます。 、公式の説明: シンプルで美しく強力な不変のスレッド - 安全。


#6. [必須] 同時実行性が高い場合、同期呼び出しではロックによるパフォーマンスの損失を考慮する必要があります。ロックフリーのデータ構造を使用できる場合は、ロックを使用しないでください。ブロックを

ロックできる場合は、メソッド本体全体をロックしないでください。オブジェクト ロックを使用できる場合は、クラス ロックを使用しないでください。


7. [必須] 複数のリソース、データベース テーブル、オブジェクトを同時にロックする場合は、一貫したロック順序を維持する必要があります。そうしないと、 によってデッドロックが発生する可能性があります。

注: スレッド 1 は、更新操作を実行する前に、すべてのテーブル A、B、および C を順番にロックする必要があります。その後、スレッド 2 のロック シーケンスも次のようにする必要があります。 A、B、C です。そうしないとデッドロックが発生する可能性があります。


#8. [必須] 同じレコードを同時に変更する場合、更新の損失を避けるために、アプリケーション層でロックするか、キャッシュ内でロックします。または データベース層は楽観的ロックを使用し、更新の基準としてバージョンを使用します。

注: アクセスごとの競合の確率が 20% 未満の場合は、楽観的ロックを使用することをお勧めします。それ以外の場合は、悲観的ロックを使用することをお勧めします。楽観的ロックの再試行回数

# は 3 回以上である必要があります。


9. [必須] マルチスレッドがスケジュールされたタスクを並行して処理するとき、Timer が複数の TimeTask を実行するとき、そのうちの 1 つがスローされた例外をキャッチしない限り

、その他 タスクは自動的に終了しますが、ScheduledExecutorService を使用するとこの問題は発生しません。


10. [推奨] CountDownLatch を使用して、非同期から同期操作を実行します。各スレッドは、終了する前に countDown

メソッドを呼び出す必要があります。スレッドがコードを実行します。 メインスレッドが countDown メソッドを実行できなくなり、タイムアウトになるまで結果が返されないように、キャッチ例外に注意して countDown メソッドを実行できることを確認してください。

注:

子スレッドによってスローされた例外スタックには、メイン スレッドの try - catch では到達できないことに注意してください。


11. [推奨事項] ランダムなインスタンスを複数のスレッドで使用することは避けてください。このインスタンスの共有はスレッドセーフですが、同じ # の競合によるパフォーマンスの低下を引き起こします。 ##シード。

説明:

ランダム インスタンスには、 java . util . Random インスタンスまたは Math . random() インスタンスが含まれます。

良い例:

JDK 7 以降では、API ThreadLocalRandom を直接使用できますが、JDK 7 より前では、

スレッドごとに 1 つのインスタンスを持つことができます。

12. [推奨事項] 初期化遅延の隠れた問題を最適化するために、二重チェック ロックを使用します (同時シナリオで) (「二重チェック ロックが壊れている」を参照してください)宣言) は、推奨される問題

(JDK 5 以降に適用) に対するより簡単な解決策の 1 つであり、ターゲット属性を volatile として宣言します。

反例:

class Foo {
private Helper helper = null;
public Helper getHelper() {
if (helper == null) synchronized(this) {
if (helper == null)
helper = new Helper();
}
return helper;
}
// other functions and members...
}

13. [参考] volatile はマルチスレッドにおける不可視メモリの問題を解決します。 1 回の書き込みと複数回の読み取りの場合、変数の同期の問題は解決できますが、 複数の書き込みがある場合、スレッドの安全性の問題は解決できません。カウント操作の場合は、次のクラスを使用して実装します: AtomicInteger count = new AtomicInteger(); count . addAndGet( 1 ); JDK 8 の場合は、LongAdder オブジェクトを使用することをお勧めします。これは、AtomicLong よりも優れたパフォーマンスを発揮します (楽観的ロックの再試行回数が減少します)。


14. 【参考】HashMap のリサイズ容量が不足している場合、同時実行性が高くデッドリンクが発生し、CPU が高騰する場合があります。

# プロセス中にこのリスクを回避するように注意してください。

15. [参考] ThreadLocal では共有オブジェクトの更新問題を解決できないため、ThreadLocal オブジェクトを static
で修飾することをお勧めします。この変数はスレッド内のすべての操作に共通であるため、静的変数として設定されます。このようなすべてのインスタンスはこの静的変数を共有します。つまり、クラスが初めて使用され、ストレージの一部のみが使用されるときにこの変数がロードされます。スペース、そのようなすべてのオブジェクト (このスレッド内で定義されている場合のみ

のみ) この変数を操作できます。