プログラマ:Javaの私は最終的にこれらの「ロック」の事を知っています

著者:千覚

Eメール:[email protected]

序文

インタビュアーは常に致命的なトリプル高並行性、高可用性、高パフォーマンスを投げていますすべてのインタビュー

ここに画像を挿入説明
私たちのプログラマはまた、3-高として知られている、仕事今日ジュエジュエは、これは、「ロック」の事で3つの高校によって複雑になると言います。

我々は、Javaがロックを持っているかを知るために必要なすべてのまず、千覚下の絵は、それが明確に(侵害た場合、メールの削除によって私に連絡してください、ネットワークから絵を)Javaのロックとの違いを説明することができると信じて

ここに画像を挿入説明

ここで千覚が「ロック」のことで、次のJava上であなたに1つずつかかります

楽観と悲観的ロックロック

ペシミスティック・ロック・コンセプト:;ロック・ライン・データベース、テーブルロック私はロックを取得するためにロックを解除するまで、常に最悪のケースを想定して、他の人がデータを変更することをデータを取るたびに、そのロックされ、他の人しか待つことができますロックを読んで、書き込みロックは、この方法です。同期とロックのJava実装クラスは、悲観的ロックの考えです。

オプティミスティック・ロックの概念:常にそれがロックされませんので、他の人がデータを変更しないというデータを取るたびに、最良の場合を想定しますが、更新はその間に判断されるとき、誰もが変更されている。一般的にベースのバージョン達成するためのメカニズムはありません。CASでのJavaの楽観的ロックは、最も一般的な方法です。

ここに画像を挿入説明

上記の考え方によると、私たちは楽観と悲観的ロックの簡単なシナリオを学ぶことができます

  1. 彼らは直接ロックを読んでいないので、オプティミスティック・ロックは、読書と少ない書き込みの場合に適用される大幅にシステムのパフォーマンスを向上させることができます。
  2. 多くの少ない読んでいったんロックが解除された後まで待つが、あなたはすぐにロックが作動するように得ることができるので、ペシミスティック・ロックは、書き込みの場合に適用されます。

ビット無知という概念があるかもしれないことを直接、私たちは、次の呼び出しのJavaを見ます

//悲观锁用synchronized实现
public synchronized  void test(){//执行相应的操作}
//悲观锁用Lock实现
Lock lock = new ReentrantLock();
public void testLock(){   
    lock.lock();
    //TODO 执行相应的操作
    lock.unlock();
}
//乐观锁
AtomicInteger atomicInteger = new AtomicInteger();
public void testCAS(){
  atomicInteger.incrementAndGet();
}
复制代码

なぜそう、より多くの私たちは、直接ではない楽観的ロックロックリソースの同期がそれを達成することができ、なぜ、私の友人のこの時間の多くが要求されますリソースの同期を確実にするためにロックされている悲観的ロックと呼ばれて見ることができるよりも参照してください、そして、覚1000上に見えます。

ここに画像を挿入説明

なぜ楽観的ロックロックリソースの同期は、それを達成することができませんか?

開始以来、私たちは楽観的ロックは、CASアルゴリズムを達成するための最も重要な方法であると言います。

CASは、比較とスワップ、その後、比較的、JDK5が追加されて交換と契約しているjava.util.concurrentであるということです。*、それ以下のクラスが実装楽観的ロックsynchronouse同期ロックからCASの異なるを使用したアルゴリズム。

CASは、3つのオペランド、持っている新しい値Bを変更するメモリ値V、旧Aの期待値を、AとVの期待値が同じメモリ値である場合のみと、メモリ値VはBに改訂された場合、または何もしません。

CASは、これは非常に強いが、私たちは、「ロック」ロックフリー道、CASを達成することを可能にされていますが、いくつかの問題があります

  1. ABAの問題CASは変更されませんが更新された場合は、変更しましたが、値がAであれば、Bになっていない、彼はAである値の下で動作時の値をチェックする必要があるので、あなたは、CAS検査を使用するときにいることがわかりますその値が変更され、実際に変更されていません。ソリューションABAの問題は、バージョン番号を使用することです。バージョン番号は、バージョン番号プラスワンが、それはABA 1A-2B-3Aとなるであろう場合に、各変数が更新され、変数の前に添加されます。

    JDK原子Java1.5パッケージの先頭からABAの問題に対処するために、クラスのAtomicStampedReferenceを提供します。このクラスの動作方法は、現在の基準が予想参照に等しく、全てがアトミック基準値に等しくなるとフラグが指定された更新値に設定されている場合、現在のマークが、予想されるフラグに等しいのcompareAndSetチェックです。

    ABAリファレンスドキュメントの問題について:blog.hesey.net/2011/09/res ...

  2. 長いサイクルタイムに大きなを費やします時間が成功したスピンCASでない場合、それは非常に大きなCPUの実行コストをもたらすでしょう。

  3. アトミック操作は、共有変数を保証することができます共有変数に対して操作を実行するとき、私たちはアトミック操作を保証するために、CASサイクル・アプローチを使用することができますが、サイクルCASを操作する複数の共有変数がアトミック動作を保証できない場合、この時間は、あなたがロック、またはAを使用することができますトリッキーな方法は、動作するように共有変数に複数の共有変数をマージすることです。例えば、I 2、J = IJ = 2Aで、マージ=、およびCASのIJで動作する2つの共有変数があります。

AtomicReferenceは、オブジェクト間の参照原子を確保するために提供開始Java1.5 JDKのクラスからは、CASの操作に複数の変数にオブジェクトを置くことができます行われます。

スピンロックと適応性のスピンロック

スピンロック:回避のスレッド同期がリソースを取得するために、一時停止し、元のスレッドがスピンロックでロックを取得するサイクルを待つ必要があることができ、頻繁にスレッドを再開する。

アダプティブスピンロック:適応型スピンロック時間が固定スピンには反映されません。スピンスレッドロックの前に同じオブジェクトのロックがちょうど勝った場合は、今のスレッドが実行されているロックを保持して、VMが相対的に用のスレッドが待機できるよう、このスピンもおそらく成功するためにあると思います長い、などの100サイクル。逆に、少しロックスピンウォンが成功した場合、その後、スピンオフプロセスがプロセッサリソースの浪費を避けるために省略することができたときに、ロックを取得した後。

ネットワークから上記の概念。

ここに画像を挿入説明

スレッド切り替えのオーバーヘッドを回避するためにスピンを待っている間、それはプロセッサ時間を取り:スピンロックを欠点。ロックが短時間に占有されている場合は、スピン効果を待っていることは非常に良いだろう。ロックが長時間占有されている一方、それは白い廃棄プロセッサリソースを通す回転します。スピンは、限られた回数(デフォルトは10で、あなたは-XX使用することができます。変更にPreBlockSpin)を超えるのであれば、待ち時間は一定の限界を持たなければならないスピンロックを得ることが成功せず、それがハングスレッドでなければなりません。JDK6は、デフォルトのスピンロックで有効になっています。

原理スピンロック実装もCASで、原則として楽観的ロックが達成され、上記CASはロックへのロックフリーの道を達成することができ、それは価値が彼の成功を変更するまでスピンロックが無限ループを追加スピンしていると述べました。

TicketLock、CLHlockとMCSlock(あなたは私に、友人にメッセージをお知りになりたい場合は、私だけでは単一の開口部の章):3つの一般的なスピンロックロック形式があります。

いいえロックしないと、偏ったロックロック、軽量かつヘビー級ロック

4つのロックは四つの状態がロックされている実際に、私がリーダーを持っていると信じて、確かにこの時間は、それが存在する場合、ロックの状態は、ロックが何であるかを尋ねました。

ここに画像を挿入説明

手のけいれんを取得するために千覚、プランと一緒に行くために、心配しないでください。

どこでそれがロックされますか?

Javaは、マークのWordのラッチヘッドオブジェクト。マーク・ワードは、オブジェクトのhashCodeおよびその他の情報を保持しているだけでなく、デフォルトのロックフラグを格納します。ランは、ロックの状態に応じて、マーク・仕事のメモリの内容を変更します。オブジェクトが配列型である場合、オブジェクト・タイプがアレイ、ヘッドと対象物2に格納されたワード幅でない場合、仮想マシン3つの記憶語は、広いヘッドオブジェクト。4バイトに等しい幅32ビットの仮想マシン、言葉では、32ビットオブジェクトに関する。ファーストクラスの知識、Java仮想マシンの関連記事を参照してください。

マークWordのコンテンツのロックがあります

メモリ内容 状態
オブジェクトのハッシュコード、世代年齢、付勢されているオブジェクトのロック(0) 01 いいえロックません
ロックレコードへのポインタ 00 軽量ロック
ヘビー級のロックを指し示すポインタ 10 ヘビーロック
バイアススレッドID、タイムスタンプバイアス、オブジェクト世代年齢は、ロック付勢されている(1) 01 バイアスされたロック

いいえロック:ロックされていないが、何のリソースは、すべてのスレッドがリソースにアクセスできるように、ロックされていないが、同時に一つだけのリソースが正常に変更することができます。

バイアスロック:バイアスロックがロックのために最適化されている間、スレッド競合状態がほとんどの場合に存在しない、同期性能を消費し、同期性能を向上させるために除去することができます。スレッドがロックを取得すると、ロックフラグがバイアスモードに入るように01であると、ヘッダセットオブジェクトであろう。偏りロックがスレッドが時間の他のスレッドで競争するために、ロックニーズをロックを保持し、その後ロックを解除されていることができます。

軽量ロック:状態競争に偏っロックスレッド1、スレッド2を取得した後、あなたは1つのロックが開催されたスレッドを取得する必要があり、それは軽量バイアスされ、ロックロックにアップグレードされます、他のスレッドはスピンの形に介して取得しようとしますロック。

ヘビー級のロック:特定の回数やロックを保持しているスレッド、スピンのスレッドは別の第三の訪問、軽量ヘビー級ロックロックのエスカレーション、オーバースピンはその後、ロック・スレッドを待ちます彼らは、ブロックされた状態になります。

全体的にロック状態のアップグレードプロセス:バイアスロック---->軽量ロック---->ヘビー級ロック

公正かつ不公平なロックロック

フェアロック:各スレッドがロックを得ることができること。

アンフェアロック:あなたは、各スレッドがロックを取得できることを保証することはできません。

ビット無知ならば、たとえば、参照するには、言語の記述があります。

ロックは正直どうかをDafan Dafanアップカフェテリアラインに行くとき、その公正ロックで公平です。

ロックはあなたが食事を築く人の目の前に並ぶことができませんカフェテリアDafanに不公平であるときは、直接Dafanは、Dafanませんでしたどのように多くの人々を制御していないことができます。この場合、ロックは不公平です。

ここに画像を挿入説明

フェアロックの中のjava、非公正のためのロック

//公平锁
ReentrantLock lock = new ReentrantLock(true);
//非公平锁
ReentrantLock lock = new ReentrantLock(false);
复制代码

あなたはなぜ、この実現を知りたい場合は、特定の原則を議論していない、あなたは私にメッセージを残すことができます。

該当するシナリオは次のとおりです。糸保持時間が長いスレッド切り替え時間よりも非株式の数はロックされ、逆に、まだ公正なロックです。

再入可能および非リエントラントロックロック

リエントラントロックロックは、メソッドロックアウトした後、まだ内部をロックすることができ、繰り返し呼び出すことができている、と(同じオブジェクトまたはクラスものとする)デッドロックは、ロックがリエントラントロックと呼ばれているように、発生しません。ReentrantLockのは同期とリエントラントロックされています。

あなたは少し無知かもしれないが、それはこのようなものは非常にシンプルであることに気づい見るためにコンセプトを見てきました。

public class Test implements Runnable{
    public static void main(String []args){
        Test test = new Test();
        for(int i = 0; i < 5; i++){
            new Thread(test).start();
        }
    }
    @Override
    public void run() {
        out();
    }

    public synchronized void out(){
        System.out.println(Thread.currentThread().getName());
        in();
    }

    public synchronized void in(){
        System.out.println(Thread.currentThread().getName());
    }
}
复制代码

//出力結果は、次のように、私たちは何のスレッドがブロックされていない見ることができるのです

スレッド2、スレッド2、スレッド4スレッド4スレッド3スレッド3スレッド1スレッド1スレッド0スレッド0

非リエントラントロックがロックアウトロックに使用することができない方法、およびこの時間の後に、何度もロックを呼び出すことはできませんされてロックがあなたがロックの内側から抜け出すだろう解放されるまでロックがブロックされます。これは、デッドロック状態が生成されます。

以下のことを実現するために、非リエントラントロック:

public class NoLock {
    private boolean isLocked = false;
    public synchronized  void lock() throws InterruptedException {
        while (isLocked){
            wait();
        }
        isLocked = true;
    }
    public synchronized void unlock(){
        isLocked = false;
        notify();
    }
}
复制代码

排他ロックと共有ロック

排他ロック:ロックは唯一の同期、一人一人のスレッド一度開催され、排他ロックReentrantLockのあることができます

共有ロック:ロックは、複数のスレッドの合計することができます。スレッドはデータのみを読み取ることができ、共有ロックを取得し、データを変更することはできません。

ReentrantReadWriteLock 2つのロックがあります「読み書きロック」のイタリア語、読み取りロック書き込みロック、総称で知らReadLockとWRITELOCK、読み取りロックは、書き込みロックは排他ロック共有ロックです

概要

Javaの「ロック」この事は、物事の原則の多くの側面がありますが、以上ですが、何千覚なしの深い導入は、一方では、それは読者がこの記事を読めば、私のレベルは、ディスク容量不足のために、一方では、十分ではありませんですので、疑いのどのような領域が私に伝えるためにメッセージを残すことができます。

最後に、私は賞賛にそれを指して、それに大丈夫、トラブルトラブルあなたの小さな手のポイントの注目感じで書かれたこの記事を読むためにあなたを請う、あなたの賞賛と注目が千覚書きの駆動力です。

2019年の終わりには、2020年の希望は、それをより良くするために、私はあなたにすべての幸せな新年を願っています。

おすすめ

転載: juejin.im/post/5e0b1b025188253aa57a645a
おすすめ