0Pricing
Java Academy · レッスン

ReentrantLock と synchronized の比較

ReentrantLock の機能(tryLock、lockInterruptibly、公平性)を synchronized キーワードと比較します。

「ReentrantLock と synchronized の比較」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJava Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Java Academyコースには全4レッスンが含まれています。

synchronizedキーワード

Javaのsynchronizedキーワードは、オブジェクトの固有ロック(モニター)を使って相互排他を実現します。シンプルですが、タイムアウト、公平性、割り込み可能性には対応していません。

class Counter {
    private int count = 0;
    
    synchronized void increment() {
        count++; // only one thread at a time
    }
    
    synchronized int get() { return count; }
}

Counter c = new Counter();
// Multiple threads can safely call increment()

ReentrantLockの基本

ReentrantLockは、java.util.concurrent.locksにある明示的なロックです。synchronizedと同じ相互排他を提供しますが、より細かく制御できます。ロックはfinallyブロックで手動で解放する必要があります。

import java.util.concurrent.locks.*;

class SafeCounter {
    private int count = 0;
    private final ReentrantLock lock = new ReentrantLock();
    
    void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock(); // always release in finally!
        }
    }
    
    int get() {
        lock.lock();
        try { return count; }
        finally { lock.unlock(); }
    }
}

tryLock: ブロッキングなしの取得

tryLock()は、ブロックせずにロックの取得を試みます。取得に成功するとtrue、別のスレッドがロックを保持している場合はfalseを返します。

ReentrantLock lock = new ReentrantLock();

if (lock.tryLock()) {
    try {
        System.out.println("Got the lock, doing work");
    } finally {
        lock.unlock();
    }
} else {
    System.out.println("Lock busy, skipping or retrying");
}

タイムアウト付きtryLock

指定した時間までロックの取得を待機します:

try {
    if (lock.tryLock(500, TimeUnit.MILLISECONDS)) {
        try {
            // work with protected resource
            System.out.println("Acquired within 500ms");
        } finally {
            lock.unlock();
        }
    } else {
        System.out.println("Timed out waiting for lock");
    }
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
}

lockInterruptibly

lockInterruptibly()は、スレッドが割り込まれない限りロックを取得します。ロック待ち中のキャンセル可能なタスクに便利です:

try {
    lock.lockInterruptibly(); // throws InterruptedException if interrupted
    try {
        // do work
    } finally {
        lock.unlock();
    }
} catch (InterruptedException e) {
    System.out.println("Interrupted while waiting for lock");
    Thread.currentThread().interrupt();
}

再入性

synchronizedとReentrantLockはいずれも再入可能です。すでにロックを保持しているスレッドは、デッドロックを起こさずに同じロックを再び取得できます:

synchronized void outer() {
    System.out.println("outer");
    inner(); // same thread re-enters — OK
}

synchronized void inner() {
    System.out.println("inner"); // same lock, same thread
}

// ReentrantLock:
ReentrantLock lock = new ReentrantLock();
lock.lock();
lock.lock(); // acquire again — hold count = 2
lock.unlock(); // hold count = 1
lock.unlock(); // hold count = 0, lock released

公平性ポリシー

公平なReentrantLockを作成すると、FIFO順にアクセスを許可できます。スループットは低下しますが、スレッドの飢餓を防げます:

// Unfair (default): no ordering guarantee, better throughput
ReentrantLock unfair = new ReentrantLock();

// Fair: threads acquire in arrival order
ReentrantLock fair = new ReentrantLock(true);

System.out.println(fair.isFair()); // true

Condition変数

ReentrantLockはConditionオブジェクトを提供します。wait()/notify()より柔軟に使用できます:

ReentrantLock lock2 = new ReentrantLock();
Condition notEmpty = lock2.newCondition();
Queue<String> queue = new LinkedList<>();

// Producer
lock2.lock();
try {
    queue.offer("item");
    notEmpty.signal(); // wake one waiting thread
} finally { lock2.unlock(); }

// Consumer
lock2.lock();
try {
    while (queue.isEmpty()) notEmpty.await(); // wait & release lock
    System.out.println(queue.poll());
} finally { lock2.unlock(); }

ReentrantLockとsynchronizedの使い分け

synchronizedを使用する場合:

  • シンプルな相互排他が必要な場合
  • タイムアウト、公平性、割り込み可能性が不要な場合

ReentrantLockを使用する場合:

  • tryLock()またはtryLock(timeout)が必要な場合
  • lockInterruptibly()が必要な場合
  • 公平な順序制御が必要な場合
  • 複数のCondition変数が必要な場合

ロック数と監視

ReentrantLockは診断用メソッドを提供します:

ReentrantLock lock3 = new ReentrantLock();
lock3.lock();
lock3.lock(); // reentrant — hold count 2

System.out.println(lock3.getHoldCount());    // 2
System.out.println(lock3.isHeldByCurrentThread()); // true
System.out.println(lock3.isLocked());        // true
System.out.println(lock3.getQueueLength());  // 0 (no waiting threads)

lock3.unlock();
lock3.unlock(); // fully released

よくあるミス: ロックせずにunlockする

現在のスレッドがロックを保持していない状態でunlock()を呼び出すと、IllegalMonitorStateExceptionがスローされます。必ずlockとunlockを組み合わせるか、try-finallyを使用してください:

ReentrantLock lock4 = new ReentrantLock();
try {
    // If lock() is never called (e.g., skipped by exception before this line)
    lock4.unlock(); // throws IllegalMonitorStateException
} catch (IllegalMonitorStateException e) {
    System.out.println("Must lock before unlock!");
}

クイックチェック

ロックが使用できない場合にブロックせず、ロックを取得するかすぐに戻ることができるReentrantLockのメソッドはどれですか?

まとめ: ReentrantLockとsynchronized

重要なポイント:

  • どちらも相互排他と再入性を提供します
  • ReentrantLockはtryLock、lockInterruptibly、公平性、Conditionを追加で提供します
  • 必ずfinallyブロックで解放してください
  • synchronizedのほうがシンプルです。その機能で十分な場合はsynchronizedを優先してください
  • タイムアウト、割り込み可能性、複数のConditionが必要な高度な状況ではReentrantLockを使用します

よくある質問

「ReentrantLock と synchronized の比較」レッスンは無料ですか?

はい。「ReentrantLock と synchronized の比較」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。

「ReentrantLock と synchronized の比較」で何を学びますか?

ReentrantLock の機能(tryLock、lockInterruptibly、公平性)を synchronized キーワードと比較します。 ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Java Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。

「ReentrantLock と synchronized の比較」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このJava Academyレッスンでコードを書いて実行できますか?

はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. ReentrantLock と synchronized の比較
  2. 読み取り・書き込み処理のための ReadWriteLock
  3. Atomic 変数:ロックなしの更新
  4. StampedLock と楽観的読み取り
← Java Academyに戻る