フェアロックとアンフェアロックの説明はあなたを忘れられないものにします

フェアロックとアンフェアロックの概念
フェアロック:簡単な例をとると、毎日夕食を食べるために5人の生徒が並んでいる必要があります。簡単にするために、これら5人の生徒それぞれに001から005までの番号を定義します。 。5人のクラスメートは先着順で並んでおり、最初のクラスメートは最初に食事をとることができます。各生徒はスレッドであり、後の生徒はこのプロセス中にキューにジャンプすることはできません。これは公正なロックです。
不当なロック:その後、クラスメートが食事を捕まえられなくなる可能性があります。食事中は、キューをジャンプすることが許可されます。このスレッド挿入動作は不公平と見なされます。たとえば、001、002、003、004の番号の生徒が最初に列に並び、005が最後に列に並び、004の後ろにあるはずでしたが、005は夕食の直後に001が残っているのを見て、飛び込みました。つまり、炊飯の順番が001-> 002-> 003-> 004-> 005から001-> 005-> 002-> 003-> 004に変わります。実際、フェアロックは通常のキューイングを意味し、アンフェアはキューをスキップすることを意味することを理解する必要があります。もちろん質問があるかもしれませんか?001が成功した後に005が挿入されますか?答えは必ずしもそうではありません。タイミングによって異なります。「005は001を見て、食事の直後に左に移動します」と言ったので、次は002になります。おそらく、ダファンおばさんは尋ねていません。 002何を食べるか、005が先頭にキューイングされているかどうかを確認し、005がキューに正常にジャンプしました。これが時間です。以下では、プログラムコードを使用して理解を深めます。
同期された不公平なロック

/**
 * @author :jiaolian
 * @date :Created in 2020-12-31 16:01
 * @description:食堂打饭:synchronized不公平
 * @modified By:
 * 公众号:叫练
 */
public class SyncUnFairLockTest {
    
    

    //食堂
    private static class DiningRoom {
    
    
        //获取食物
        public void getFood() {
    
    
            System.out.println(Thread.currentThread().getName()+":排队中");
            synchronized (this) {
    
    
                System.out.println(Thread.currentThread().getName()+":@@@@@@打饭中@@@@@@@");
            }
        }
    }

    public static void main(String[] args) {
    
    
        DiningRoom diningRoom = new DiningRoom();
        //让5个同学去打饭
        for (int i=0; i<5; i++) {
    
    
            new Thread(()->{
    
    
                diningRoom.getFood();
            },"同学编号:00"+(i+1)).start();
        }
    }
}
复制代码

上記のコード:食堂を表す内部クラスDiningRoomを定義します。getFoodメソッドでは、同期ロックを使用して、DiningRoomインスタンスオブジェクト(22行目のdiningRoomオブジェクト)を指すようにこれを変更します。メインクラスでは、 001から005までの5人の生徒を同時に夕食に行かせます。最初に並んだ生徒が最初に食事をとれるかどうかをテストするために使用されますか?次の図に示すように、プログラムを実行して実行結果の1つを取得します。002-> 004-> 001-> 003-> 005の学生が最初にキューに移動しますが、食事の順序は002-> 003->です。 001-> 004-> 005、2人のクラスメート003と001がキューに飛び込んで、004の前に挿入されたことを意味します。実行プロセスを詳細に分析します。002は最初に夕食のロックを取得し、ロックを解放しました。夕食の鍵を握ったのは004であるはずですが(004は003の前に並んでいたため)、003は鍵を握り、食事を取り、鍵を解放しました。これは、キューにジャンプするのは初めてです。現在、ロックを取得するのはまだ004ですが、001によって再度取得されました。ロックが解放された後、004によって取得されました。これは、キューにジャンプする2回目であり、次に004-> 005で取得します。ロックし、ロックを解除して、プログラムを実行します。完了します。003と001がキューにジャンプするため、コードを使用して、同期が不公平なロックであることを証明します。次に、ReentrantLockのフェアロックとアンフェアロックについて見ていきます。
ここに写真の説明を挿入
ReentrantLock不公平なロック

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author :jiaolian
 * @date :Created in 2020-12-31 11:11
 * @description:非公平锁测试  在获取锁的时候和再获取锁的顺序不一致;
 * @modified By:
 * 公众号:叫练
 */
public class UnFairLockTest {
    
    

    private static final Lock LOCK = new ReentrantLock(false);

    //食堂
    private static class DiningRoom {
    
    
        //获取食物
        public void getFood() {
    
    
            try {
    
    
                System.out.println(Thread.currentThread().getName()+":正在排队");
                LOCK.lock();
                System.out.println(Thread.currentThread().getName()+":@@@@@@打饭中@@@@@@@");
            } catch (Exception e) {
    
    
                e.printStackTrace();
            } finally {
    
    
                LOCK.unlock();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
    
    
        DiningRoom diningRoom = new DiningRoom();
        //让5个同学去打饭
        for (int i=0; i<5; i++) {
    
    
            new Thread(()->{
    
    
                diningRoom.getFood();
            },"同学编号:00"+(i+1)).start();
        }
    }
}
复制代码

上記のコード:コードの13行目でLock LOCK = new ReentrantLock(false)を定義しました。ReentrantLockのパラメーターはfalseであり、不公平なロックを示します。上記のコードはLOCK.lock()でロックし、LOCKでロック解除する必要があります。 .unlock()。tryおよびfinallyコードブロックに配置する必要があります。目的は、tryでのロック後にコードが異常である場合、ロックが最終的に実行されるLOCK.unlock()であり、ロックはいつでも解放できます。 。メインクラスでは、001から005までの5人の生徒を同時に夕食に行かせ、下図のように実行結果の1つを取得します。001-> 004-> 005-> 003-> 002人の生徒はキューが最初ですが、ディナーの順序は001-> 005-> 004-> 003-> 002です。ここでは、005がキューにジャンプし、004の前に挿入されています。実行プロセスを詳細に分析します。001は最初にロックを取得してロックを解放しました。次に、004が最初にキューに入れられたため、ロックを取得するはずでしたが、005は004と005の前にロックを取得しました。004の後、食事は最初に提供されますが、これは不公平なロックです。後続の実行結果が最初に実行され、プログラムが終了します。コードを使用して、ReentrantLockが不当なロックであることを証明します。次に、フェアロックとしてのReentrantLockの別の状況を見てみましょう。
ここに写真の説明を挿入
ReentrantLockフェアロックは
上記のケースに基づいています。コードを繰り返さず、上記のコードの13行でprivate static final Lock LOCK = new ReentrantLock(false)を変更します。パラメーターはfalseからtrueに変更されます。privatestatic final Lock LOCK = new ReentrantLock(true);何度実行しても、結論を導き出すことができます。つまり、列の子供用の靴を最初に提供でき、列にジャンプできないことは、公正なロックを反映しています。
ここに写真の説明を挿入
。ReentrantLock基本原則
ReentrantLockは、AbstractQueuedSynchronizer(抽象キューシンクロナイザー、略してaqs)に基づいて実装されます。aqsの最下層は、スレッドを同期するための先頭の二重リンクリストを維持します。リンクリストの各ノードはノードで表されます。各ノードはスレッド情報を記録します。下位ノード。ノードステータスなどの情報については、aqsはノードのライフサイクルを制御します。次の図に示すように、aqsには条件付きキューも含まれています。ロックと条件付きキュー(条件)には1対多の関係があります。つまり、ロックは複数の条件付きキューに対応できます。スレッド間の通信は条件付きキューにあります。 Synchronizedには、wait、notify / notifyAllで実装される条件キューが1つだけあります。ここでは詳しく説明しません。「産卵の例:マルチスレッド通信プロデューサーとコンシューマーの待機/通知と条件/待機/信号条件キュー」と「同期使用原理とロックの最適化とアップグレードプロセス(インタビュー)」は私の記事を読むことができます、明確で単純なケースがたくさんあります。条件付きキューは、リンクリストの形式でも存在します。Lockはjucパッケージに基づいて実装され、synchronizedはc ++に基づくネイティブメソッドです。
ここに写真の説明を挿入
参照:「2020年の最新のJavaの基本と詳細なビデオチュートリアルおよび学習ルート!

元のリンク:https://juejin.cn/post/6913524662160850951

おすすめ

転載: blog.csdn.net/weixin_46699878/article/details/112179002