Java
 Computer >> コンピューター >  >> プログラミング >> Java

Javaのsynchronizedブロックとは?同期処理が必要な場面と使い方を実例付きで解説

synchronizedブロックとは、メソッド内の特定のリソースに対して同期(スレッドセーフな排他制御)を行うために使用するコードブロックです。共有リソースを持つオブジェクトをロックする役割を担い、synchronizedメソッド全体を対象とする場合と比べて、同期の適用範囲が狭くて済むのが特徴です。

同期範囲を必要最小限に抑えられるため、パフォーマンスへの影響を軽減しながら競合状態(レースコンディション)を防ぎたい場面で特に有効です。

構文

synchronized(object) {
    // 同期したいコードブロック
}

ここで object は、同期の対象となるオブジェクトへの参照です。synchronizedブロックを使うと、そのオブジェクトのメンバーであるメソッドの呼び出しは、現在のスレッドがオブジェクトのモニター(ロック)に正常に入った後にのみ実行されることが保証されます。

使用例:チケット予約システム

以下の例では、残席数を管理するチケットカウンターに対して、複数のスレッドから同時に予約リクエストが発生する状況を想定しています。synchronizedブロックで囲むことで、残席数の確認と減算処理が他のスレッドによって割り込まれることなく、一貫して実行されます。

class TicketCounter {
    int availableSeats = 2;
    void bookTicket(String name, int numberOfSeats) {
        if((availableSeats >= numberOfSeats) && (numberOfSeats > 0)) {
            System.out.println(name + " : " + numberOfSeats + " Seats Booking Success");
            availableSeats -= numberOfSeats;
        } else {
            System.out.println(name + " : Seats Not Available");
        }
    }
}
class TicketBookingThread extends Thread {
    TicketCounter tc;
    String name;
    int seats;
    TicketBookingThread(TicketCounter tc, String name, int seats) {
        this.tc = tc;
        this.name = name;
        this.seats = seats;
    }
    public void run() {
        synchronized(tc) { // synchronizedブロック
            tc.bookTicket(name, seats);
        }
    }
}
public class SynchronizedBlockTest {
    public static void main(String[] args) {
        TicketCounter tc = new TicketCounter();
        TicketBookingThread t1 = new TicketBookingThread(tc, "Adithya", 2);
        TicketBookingThread t2 = new TicketBookingThread(tc, "Jai", 2);
        t1.start();
        t2.start();
    }
}

実行結果

Adithya : 2 Seats Booking Success
Jai : Seats Not Available

この例では、最初のスレッド「Adithya」が残り2席すべてを予約したため、次のスレッド「Jai」は空席がないとして予約に失敗します。もしsynchronizedブロックがなければ、両方のスレッドが同時に残席数をチェックし、在庫以上の座席が売れてしまうなどの不整合が発生する可能性があります。

synchronizedブロックを使うべきポイント

  • 複数のスレッドから同じ共有リソース(インスタンス変数など)へ読み書きする場合
  • メソッド全体ではなく、クリティカルセクション(競合が発生し得る一部のコード)だけを同期したい場合
  • synchronizedメソッドによる広範囲なロックがパフォーマンス低下につながる場合

このように、synchronizedブロックは同期の粒度を細かく制御できるため、マルチスレッド環境でのデータ整合性を保ちつつ、効率的な並行処理を実現するための重要な手法です。

  1. Javaのpack()メソッドとは?使い方とsetSize()との違いを解説

    pack()メソッドは、JavaのWindowクラスで定義されているメソッドで、フレーム内のすべてのコンポーネントがそれぞれの推奨サイズ(preferred size)以上で表示されるように、ウィンドウのサイズを自動的に調整します。 代替手段として、setSize()メソッドやsetBounds()メソッドを呼び出して、フレームのサイズを明示的に指定する方法もあります。しかし一般的には、pack()メソッドを使用する方がsetSize()よりも推奨されています。その理由は、pack()がフレームのサイズ決定をレイアウトマネージャーに委ねることができ、レイアウトマネージャーはプラットフォーム間の

  2. SAP Java Connector(JCo)で独自のDestinationDataProviderを実装・登録する方法

    SAP Java Connectorで独自のDestinationDataProvider(DDP)を利用するSAP Java Connector(JCo)では、SAPシステムへの接続情報(デスティネーション)の管理方法を柔軟にカスタマイズできます。標準的な jco.destination ファイルに依存する代わりに、DestinationDataProvider(DDP)インターフェースを独自に実装することが可能です。DestinationDataProviderとはDestinationDataProviderは、SAPシステムへの接続に必要なホスト名、システム番号、クライアント番号、ユー