並行プログラミングJavaのロック

再入可能ロック

ツールの一貫性、複数の実装では、Javaプラットフォーム(例えば同期(ヘビー級など)とReentrantLockの(軽量)、など)を確保するために、同時共有データとしてロックします。これらのロックは、私たちの開発のための利便性を提供するためのプランを書かれています。

また、ロックを取得するために外側の関数の後に同一のスレッドを参照して、再帰的ロックとして知られているリエントラントロックは、内側の再帰関数は依然としてロックコードを取得しなければならないが、影響を受けません。

ReentrantLockのJAVA環境では、ロックリエントラントを同期しています

同期:

public class Test implements Runnable {
    public  synchronized void get() {
        System.out.println("name:" + Thread.currentThread().getName() + " get();");
    }

    public synchronized  void set() {
        System.out.println("name:" + Thread.currentThread().getName() + " set();");
        get();
    }

    @Override
    public void run() {
        set();
    }

    public static void main(String[] args) {
        Test ss = new Test();
        new Thread(ss).start();
        new Thread(ss).start();
        new Thread(ss).start();
        new Thread(ss).start();
    }
}

ReentrantLockの:

public class Test02 extends Thread {
    ReentrantLock lock = new ReentrantLock();
    public void get() {
        try{
            lock.lock();
            System.out.println(Thread.currentThread().getId());
        }catch (Exception e){

        }finally {
            lock.unlock();
        }
    }
    public void set() {
        try{
            lock.lock();
            System.out.println(Thread.currentThread().getId());
            get();
        }catch (Exception e){

        }finally {
            lock.unlock();
        }
    }
    @Override
    public void run() {
        set();
    }
    public static void main(String[] args) {
        Test ss = new Test();
        new Thread(ss).start();
        new Thread(ss).start();
        new Thread(ss).start();
    }

}

関数自体が終了した後、通常の状況下ではロックを解除し、上記の二つの方法は、ロック機能である再呼び出し機能がロックを必要とされてきた、無再入ならば、あなたは新しいロック機能を必要とすることは意志を呼び出しますこれは、デッドロックが発生します。再利用可能なロックは、再帰のために非常に重要です。

第二に、読み書きロック

プログラムでは、共有リソースへの読み取りおよび書き込み操作の数を含み、書き込み動作は、それほど頻繁に読み取ることはありません。書き込み動作の不在下で、2つのスレッドが何の問題もなく、リソースを読み取るためには、複数のスレッドが同時に共有リソースを読み取ることができる可能にすべきです。

しかし、スレッドがある場合は、これらの共有リソースを書きたい、もはや(すなわち:読む - 、共存読むことができます - 書き込みは共存できない、書き込み - 書き込みは共存できません)読み取りまたは書き込みをするために他のスレッドにリソースを持っていないはずです。

これは、この問題を解決するために、読み取り/書き込みロックが必要です。Java5ではjava.util.concurrentパッケージは、すでに読み書きロックが含まれています。

public class Cache {
    static Map<String, Object> map = new HashMap<String, Object>();
    static ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
    static Lock r = rwl.readLock();
    static Lock w = rwl.writeLock();

    // 获取一个key对应的value
    public static final Object get(String key) {
        
        try {
            r.lock();
            System.out.println("正在做读的操作,key:" + key + " 开始");
            Thread.sleep(100);
            Object object = map.get(key);
            System.out.println("正在做读的操作,key:" + key + " 结束");
            System.out.println();
            return object;
        } catch (InterruptedException e) {

        } finally {
            r.unlock();
        }
        return key;
    }

    // 设置key对应的value,并返回旧有的value
    public static final Object put(String key, Object value) {
        
        try {
            w.lock();
            System.out.println("正在做写的操作,key:" + key + ",value:" + value + "开始.");
            Thread.sleep(100);
            Object object = map.put(key, value);
            System.out.println("正在做写的操作,key:" + key + ",value:" + value + "结束.");
            System.out.println();
            return object;
        } catch (InterruptedException e) {

        } finally {
            w.unlock();
        }
        return value;
    }

    // 清空所有的内容
    public static final void clear() {
        try {
            w.lock();
            map.clear();
        } finally {
            w.unlock();
        }
    }

    public static void main(String[] args) {
        new Thread(new Runnable() {

            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    Cache.put(i + "", i + "");
                }

            }
        }).start();
        new Thread(new Runnable() {

            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    Cache.get(i + "");
                }

            }
        }).start();
    }
}

第三に、悲観的ロック、オプティミスティックロック

1、楽観的ロック

常に私は並行性の問題、データを取得し、データを変更する他のスレッドがないことを信じるたびは思うん、それはロックされませんが、更新は別のスレッドを決定する際にデータが存在しないその前に修正、一般的に達成するために、バージョン番号またはCAS操作機構を使用しています。

バージョン:通常プラスデータのバージョン番号は、データテーブル内のバージョンフィールドであるデータの数が変更され、データが変更されたとき、プラスバージョン値を表します。データの読み取り中に更新を送信するときだけ更新は、現在のデータベース内のバージョンと等しい値であるときにバージョンを読み取る、または再試行する場合、データ値を更新するスレッドAは、バージョン値を読み取るする場合更新が成功するまで更新。

コアSQL文:

更新テーブルセットX = X + 1、バージョン=バージョン+ 1ここで、ID =#{ID}とバージョン=#{バージョン}。

CAS動作:即ち、比較及びスワップ、又は比較セット、3つのオペランド、データメモリ値、期待値、新しい値を含みます。更新する必要がある場合、再試行が失敗した場合に等しいが、一般的なスピン操作、新しい値で更新された場合にメモリの現在の値が等しい前に、値をとると判定される、すなわち連続的に再試行。

2、悲観的ロック

常に最悪のケースを想定し、他のすべてのスレッド修正は、データをフェッチするとき、それはロック(ロックを読み、ロック、行ロックなどの書き込み)のデータにアクセスしたい他のスレッドは、あなたがブロックされてハングアップする必要がある場合、になると思います。このような行ロックなど、データベースの実装に依存して読み書きできるロック、思考は悲観的ロックで同期、Javaで、操作の前にロックされています。

IV - アトム

java.util.concurrent.atomicパッケージ: - 単一の変数でロック解除のAtomガジェットバッグ支持スレッドセーフなプログラミング

アトミック読み取りおよび条件をサポートするために、揮発性変数一般化の一種に対応するアトミック変数クラス - 変更 - 書き込み操作。

AtomicIntegerは、int型の値を表しており、提供し得るとメソッドを設定し、これらの揮発性int型の変数は読み取りと書き込みで同じ意味記憶を持っています。それはまた、(揮発性変数と同じ効果は、このメソッドが成功した場合、それは読取り/書込みメモリで実現される)方法、及び原子、増分を追加のcompareAndSet原子の方法を提供する等をデクリメント。上面のAtomicIntegerカウンター拡張クラスのような非常に、それは同時実行のための直接的なハードウェアサポートを活用するため、競争の場合には、高い拡張性を提供することができます。

なぜ原子力カテゴリは
CAS:比較とスワップして、それが交換さ比較します。

JDK5増加と契約java.util.concurrentの*、次のクラスが楽観的ロックsynchronouse同期ロック異なるCASを用いたアルゴリズムを実装すること。mysqlのフィールドの同様に楽観的ロックバージョン

複数のスレッドが同じ変数にアクセスする場合は、パッケージのクラスを使用することができます

  • AtomicBoolean
  • AtomicInteger
  • AtomicLong
  • AtomicReference

五、CASノーロックモード

CAS:比較とスワップ、その後、それが交換さ比較。
JDK5増加と契約java.util.concurrentの*、次のクラスが楽観的ロックsynchronouse同期ロック異なるCASを用いたアルゴリズムを実装すること。JDK 5のJava言語は、これは排他ロックであることを保証するために、synchronizedキーワードによって同期される前に、それはまた、悲観的ロックです。

1、CASアルゴリズムを理解します

  • (1)ロックと比較して、比較交換(以下、CASという)プログラムをより複雑にするように見えます。しかし、その非ブロッキングのために、その自然免疫をデッドロック、およびスレッド間の相互作用は、小型のロック・ベースの方法よりもはるかに多くのです。さらに重要なことは、何のロック競合のオーバーヘッドを持っていないためにロックフリーな方法の使用は、オーバーヘッド頻繁に起因するいかなるスレッド間のスケジューリングが存在しないので、ロックベースのアプローチよりも優れた性能を持っています。
  • (2)ロックフリーの利点は:
    まず、高い同時実行の場合には、それはプログラムよりも優れた性能は、ロックを持っている、
    それは本質的にデッドロックの免疫秒です。
  • (3)プロセスCASアルゴリズムはこれです:それは三つのパラメータCAS(V、E、N)を含有する:Vが更新される変数を表し、Eは、N、新しい値を表し、期待値を表します。値がV E値に等しい場合のみ、VとE値の値が異なっている場合、他のスレッドが更新された場合、それは、V Nの値を設定し、現在のスレッドは何もしません。最後に、CASはVの現在の実際の値を返します。(Vは可変メインスレッドを更新するために、メインメモリの値を表し、Eは、ワーキングメモリ、ローカルメモリの期待値を表し、Nは、新しい値を表します)
  • (4)CAS操作が行われている、それは常に彼が成功した操作を完了することができます信じて、楽観的な態度を保持します。複数のスレッドが同時にCASの運転変数を使用する場合は、一つだけが勝つ、と正常に更新され、残りは失敗しますします。スレッドの失敗が中断されることはありません、だけで失敗して再試行することができ、もちろん、スレッドが操作を中止失敗を許可することを告げられます。この原理に基づき、CASは何もロックがなくても動作し、他のスレッドは、現在のスレッドに干渉し、それを適切に処理するために見つけることができます。
  • (5)要するに、CASはつまり、あなたはこの変数は、現在のようになっているはずだと思い、追加的な期待を与える必要があります。変数はあなたが想像するものではない場合、それは前に他の誰かによって変更されたことを意味します。あなたが再読み込み、再びうまく修正してみてください。
  • (6)ハードウェアレベルで、最新のプロセッサは既にCASコマンドの微粒化をサポートします。JDK 5.0の後、仮想マシンは仮想マシンで同時動作と同時のデータ構造、および、そのような操作を実現するために、このコマンドを使用することができますどこにでもあると言うことができます。

2、CASの欠点

CASは明白な問題、すなわち、ABAの問題があります。

質問:最初の読み取りがある変数V、および時間は、それはまだ準備ができて、割り当てAでチェックする場合は、それがその価値はまだ別のスレッドが改訂されていない説明することができますか?

Bが戻ってAに、この期間中に変更、およびされていた場合には、そのCAS操作が誤って、それが修正されていないと信じています。この状況では、Javaの契約とクラスAtomicStampedReferenceを参照マーカー原子を提供するために、それは、CASバージョンコントロール変数値の正確さを保証することができます。

個人ブログのカタツムリ

おすすめ

転載: www.cnblogs.com/codeobj/p/11718079.html