Reentrant Lockを使ってスレッド同期を実現します。


Javaマルチスレッドでは、synchronizedキーを使用してスレッド間の同期相互反発を実現することができますが、JDK 1.5にRentrantrant Lock類を追加すると同様の効果が得られます。さらに、嗅覚ロック、分岐多重通知などの機能が拡張機能にもより強くなり、使用上もsynchronizedより柔軟になります。
Reentrant Lockの使用例を説明します。
まずService類です。同期が必要なクラスです。
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class MyService {
    private Lock lock = new ReentrantLock();   //     

    public void testMethod(){
        lock.lock();                      //     ,     
        for (int i=0;i<5;i++){
            System.out.println("Thread name:"+Thread.currentThread().getName()+" "+(i+1));
        }
        lock.unlock();                 //        
    }
}
スレッド類とテストクラスMyThreadは、4つのスレッドを作成し、各スレッドは同じServiceオブジェクトで初期化し、スレッドのrun方法はserviceのtestMethod方法を実行します。
public class MyThread extends Thread{
    private MyService service;

    public MyThread(MyService service){
        super();
        this.service = service;
    }
    @Override
    public void run(){
        service.testMethod();
    }
    public static void main(String[] args){
        MyService service = new MyService();
        MyThread t1 = new MyThread(service);
        MyThread t2 = new MyThread(service);
        MyThread t3 = new MyThread(service);
        MyThread t4 = new MyThread(service);

        t1.start();t2.start();t3.start();t4.start();
    }
}
プログラム出力は以下の通りです。各スレッド間で同期して実行されているのが見えます。一つのスレッドがリリースロックを実行した後、他のスレッドが実行できます。
Thread name:Thread-1 1
Thread name:Thread-1 2
Thread name:Thread-1 3
Thread name:Thread-1 4
Thread name:Thread-1 5
Thread name:Thread-2 1
Thread name:Thread-2 2
Thread name:Thread-2 3
Thread name:Thread-2 4
Thread name:Thread-2 5
Thread name:Thread-0 1
Thread name:Thread-0 2
Thread name:Thread-0 3
Thread name:Thread-0 4
Thread name:Thread-0 5
Thread name:Thread-3 1
Thread name:Thread-3 2
Thread name:Thread-3 3
Thread name:Thread-3 4
Thread name:Thread-3 5
また、Service類の複数の方法(例えば、A、B方法)の内部でロックを呼び出した場合、他のスレッドは、一つのスレッドが方法Aにある場合、B方法を実行できない。つまりロックは、synchronizedメソッドと同じで、ロック・ロック()を呼び出すスレッドが持つものは「対象ロック」(対象モニター)です。同じ時刻には、一つのスレッドだけが対象ロックを獲得することができます。
ロックの他の使用については以下の通りです。
1、公平性と不公平性ロックロックロックは「公平ロック」と「不公平ロック」に分けられています。公平ロックはスレッド取得の順番がスレッドロックの順に割り当てられています。先に得られたFIFOの順番を表しています。アンフェアロックとは、ロックを獲得するフライング機構であり、ランダムにロックを獲得するものであり、公平ロックとは違って、先に来たものは必ずしも先にロックを獲得するとは限らない。ロックの構造関数には次のようなものがあります。
 //              ReentrantLock。
ReentrantLock(boolean fair) 
2、方法get HoldCount()方法get HoldCount()の役割は、現在のスレッドがこのロックを保持している個数を調べること、つまりロック()メソッドを呼び出す回数です。使用方法は:
try{
    lock.lock();
    System.out.println(lock.getHoldCount());
    serviceMethod();
}finally{
    lock.unlock();
}
3、方法getQueueueLength()は、このロックを取得するスレッドの推定数を返します。
4、方法get WaitQueueueLength(Condation condition)の役割は、このロックに関連する所定の条件のCondationを待つスレッド推定数を返すことであり、例えば5スレッドがあり、各スレッドが同じconditionオブジェクトのawait()方法を実行すると、get Wait QueueLength(Condation)メソッドを呼び出した時に戻るint値は5.
5、方法lockInterruptibly()の役割は、現在のスレッドが中断されていない場合には、ロックを取得し、中断されている場合には異常な方法bootlean tryLock()が発生するのは、呼び出し時のみロックが他のスレッドに保持されていない場合にのみ、このロックを取得することである。方法ブックlean tryLock(long timeout,TimeUnit unit)の役割は、所定の待ち時間内にロックが他のスレッドに保持されておらず、現在のスレッドが中断されていない場合に取得することである。
「Javaマルチスレッドプログラミングコア技術」を参照してください。
ロックはfinallyブロックからリリースしなければなりません。さもなくば、保護されたコードが異常を投げたら、ロックは永遠に釈放されないかもしれません。この違いはよさそうですが、実はとても重要です。finallyブロックの中でロックを解除することを忘れて、プログラムの中で1つの時限爆弾を残すかもしれなくて、ある日爆弾が爆発する時、あなたはとても大きい力を費やして源を探し当てることができます。同期を使うと、JVMはロックが自動的に解除されることを確認します。参考:Java理論と実践:JDK 5.0でより柔軟で、より伸縮性のあるロック機構http://www.ibm.com/developerworks/cn/java/j-jtp10264/index.html
2016.8.9「実戦Java高併合プログラム設計」を読んで追加しました。1.RentrantLockは「再入ロック可能」と呼ばれています。一つのスレッドが何度もロックされていますので、ロックを取得するたびに参照カウントが増加します。2.RentrantrantLockにはロックを取得する方法があります。この方法はロックを取得し、相応の中断能力を備えています。4.リロック構造方法public ReentrantLock(boolean fair)は、スレッドがロックを取得する際の公平性を保証することができるが、性能に影響がある。5.ReadWriteLockも良いところですよね。