【Java同時プログラミング実戦】-ロック

5420 ワード

記事の転載先:http://cmsblogs.com/?p=1649
javaには前のブログで紹介されたsynchronizedと、synchronizedより強力でリードしたロック機構があります.ロックは、スレッドがコードの臨界領域にある場合、もう一つのスレッドが臨界領域に入らないことを確認し、synchronizedに対してロックインターフェースとその実現類がより強力で柔軟なロック機構を提供する.
シンプルなロック
synchronizedを使う時、私達はこのようにロックを使います.
public class ThreadTest {
    public void test(){
        synchronized(this){
            //do something
        }
    }
}
synchronizedは、同じ時間にdosomethingを実行するスレッドが一つしかないことを確認することができます.以下はロックを使ってsynchronizedに代えます.
public class ThreadTest {
    Lock lock = new Lock();
    public void test(){
        lock.lock();
        //do something
        lock.unlock();
    }
}
ロック()方法はロックの実例となるオブジェクトをロックするので、ロックオブジェクトのロック()メソッドを呼び出すスレッドは全てブロックされ、ロックオブジェクトのロック()方法が呼び出されるまで止まる.
【以下の引用:Java中の錠】
public class Lock{
    private boolean isLocked = false;

    public synchronized void lock() throws InterruptedException{
        while(isLocked){
            wait();
        }
        isLocked = true;
    }

    public synchronized void unlock(){
        isLocked = false;
        notify();
    }
}
isLockedがtrueである場合、ロック()を呼び出すスレッドがwait()で呼び出されて待ちます.このスレッドがnotify()から呼び出されなくてもwait()から戻ることを防ぐために、このスレッドはisLocked条件を再確認して、現在安全に実行できるかどうかを決めるために、スレッドが呼び覚まされたということではなく、再度待つ必要があります.isLockedがfalseであれば、現在スレッドはwhileループを終了し、isLockedをtrueに戻して、他のlockメソッドを起動しているスレッドにロックをかけることができます.
ロックの公平性
公平性の対立は空腹である.何が「空腹」ですか?他のスレッドがCPUを占拠していて、CPUの実行時間が得られない場合は、スレッドを「空腹死」と呼びます.飢餓を解決する方案は「公平性」と呼ばれます.すべてのスレッドはCPUの実行機会を公平に獲得できます.
スレッドの飢餓には主に以下のいくつかの理由があります.
優先度の高いスレッドは、すべての低優先スレッドのCPU時間を丸飲みにする.スレッドごとに優先度を個別に設定できます.1から10までです.優先度が高いスレッドほどCPUを得る時間が多い.ほとんどの応用に対して優先度の値を変えないほうがいいです.
スレッドは、同期ブロックに入るのを待つ状態で永久に塞がれます.javaの同期コードエリアはスレッド空腹を引き起こす重要な要素である.javaの同期コードブロックは、スレッドに入る順序を保証しません.これは、理論的に1つ以上のスレッドが存在することを意味し、同期コードエリアに入ろうとすると、他のスレッドが常に彼より優れているため、CPUの実行機会が得られずに「飢餓死」してしまう.
スレッドは、完成を待つ対象が自分自身にもあるということです.複数のスレッドがwait()方法で実行されている場合、notify()を呼び出しても、どのスレッドが起動されるかは保証されず、任意のスレッドが待ち続けられている可能性があります.このため、スレッドがいつも呼び覚まされるのを待つというリスクがあります.
スレッド「空腹」の問題を解決するために、ロックを使って公平性を実現することができます.
ロックの可搬性
スレッドが他のスレッドによってロックを持つオブジェクトを要求すると、スレッドがブロックされることを知っていますが、スレッドが自分のロックを持つオブジェクトを要求した場合、成功しますか?答えは成功できます.成功の保障はスレッドロックの「再入力性」です.
「重入可能」とは、ブロックを必要とせずに自分の内部錠を再び獲得できることを意味します.以下のとおりです
public class Father {
    public synchronized void method(){
        //do something
    }
}
public class Child extends Father{
    public synchronized void method(){
        //do something 
        super.method();
    }
}
上のコードは再入力できない場合はロックされます.childのmethod()を呼び出すと、まず親タイプFatherの内蔵ロックを取得してChildの内蔵錠を取得します.親タイプのメソッドを呼び出すと、再び親タイプの内蔵錠を外す必要があります.再入力しないと、デッドロックに陥る可能性があります.
javaマルチスレッドの再入力可能な実装は、各ロックに関連する1つの要求によって計算され、1つの占有スレッドが計算され、0としてカウントされると、ロックは占有されていないと考えられ、任意のスレッドはロックの占有権を得ることができる.あるスレッド要求が成功すると、JVMはこのロックの保有スレッドを記録し、カウントを1に設定します.このとき、他のスレッドがロックを要求すると、待つ必要があります.このスレッドがロックの取得要求を再度要求すると、カウントは+1となる.占有スレッドが同期コードブロックを終了すると、カウントは−1となり、0になるまでロックを解除する.この時、他のスレッドがロックの占有権を獲得する機会があります.
ロックとその実現類
java.util.co ncurrent.locksは、ロックと待ち受け条件のためのフレームワークとクラスを提供しています.内蔵同期とモニタとは違って、フレームはより柔軟にロックと条件を使用することができます.そのクラス構成図は以下の通りです.
Reentrant Lock:再入力可能な相互反発ロックは、ロックインターフェースの主要な実現である.
Reentrant ReadWriteLock:
ReadWriteLock:ReadWriteLockは一対の関連ロックを維持しています.一つは読み取り専用の操作に使います.もう一つは書き込み操作に使います.
Semaphore:一つのカウント信号量.
接続条件は、スレッドがロックを取得し、待つ条件が満たされているかどうかを確認することが目的です.
CyclicBarrier:同期補助クラスは、スレッドのセットが互いに一定の共通バリアポイントに到達するまで待つことができます.
これらのクラスについて詳細に説明します.
参考資料:
1、Javaの中の錠
2、【Java合併性とマルチスレッド】飢えと公平