ProgrammingJavaミドル/バックエンド開発者

Javaのスレッド処理とスレッドセーフティの確保について何を知っていますか?

Hintsage AIアシスタントで面接を突破

回答。

Javaのスレッド処理は、ThreadRunnable、およびjava.util.concurrentパッケージのクラスを使用して実装されています。スレッドセーフティを確保するためには、さまざまな同期メカニズムが使用されます:

  • 同期ブロック/メソッドsynchronized)を使用すると、複数のスレッドが競合することなく共有データにアクセスできます。
  • volatileは、スレッド間で変数の変更が可視化されることを保証します。
  • java.util.concurrentのクラス(例えば、ReentrantLockSemaphoreAtomicIntegerConcurrentHashMap)は、より柔軟な同期方法を提供します。

同期の例:

public class Counter { private int count = 0; public synchronized void increment() { count++; } public int getCount() { return count; } }

原子クラスを使用した例:

import java.util.concurrent.atomic.AtomicInteger; public class AtomicCounter { private AtomicInteger count = new AtomicInteger(0); public void increment() { count.incrementAndGet(); } public int getCount() { return count.get(); } }

注意が必要な質問。

volatileキーワードは、int型のカウンターのインクリメント時にスレッドセーフティを保証しますか?

回答: いいえ。volatileは、スレッド間の値の可視性のみを保証し、操作の原子性は保証しません。インクリメントは原子操作ではなく(count++は読み込み、増加、書き込みから成ります)、データの損失が発生する可能性があります。スレッドセーフなインクリメントには、同期やAtomicIntegerのようなクラスが必要です。

volatile int count = 0; // count++はスレッドセーフではありません!

トピックの細かい知識が欠如していることによる実際のエラーの例。


物語

オンラインストアで、ボーナスカウントがvolatileカウンターを介して更新されていました。負荷が高まる中、数千人のユーザーが商品を注文し、一部のボーナスがcount++のスレッド競合により失われました。


物語

従業員は、マルチスレッドアプリケーション内のプロデューサーとコンシューマー間の共有バッファとして通常のArrayListを使用しており、その結果ConcurrentModificationExceptionが発生しました。解決策は、synchronizedブロックを使用するか、CopyOnWriteArrayListに置き換えることでした。


物語

支払い処理を行う開発者は、「金額を確認して引き落とす」という操作を2つの無関係なメソッドで行っていました。高負荷の状態では、原子トランザクションとロックを導入するまで、二重請求が発生していました。