JUC クラス (ConcurrentHashMap、CopyOnWriteArrayList、CopyOnWriteArraySet、補助クラス) ReentrantLock および Synchronized

JUCクラス

hashMap はスレッドセーフではないため、同時に操作することはできません

HashTable はスレッドセーフであり、変更が同期されています。ロックを put() に直接追加するのは非効率です。これはハッシュ テーブル全体をロックするのと同じです。同時実行性が低い状況でも使用できます。排他的ロック

同時ハッシュマップ

ConcurrentHashMapはスレッドセーフであり、ロックセグメンテーション機構を採用しており、ハッシュテーブル全体をロックしないが、jdk8以降はセグメントロックを使用せず(位置ごとにロックフラグオブジェクトを作成)、CASの考え方+同期型で実装されている

挿入する際には、ハッシュテーブルに対応する位置が先頭ノードであるかどうかを確認し、先頭ノードであればCAS機構(ループ検出)を利用して先頭位置にデータを挿入します。

この位置にすでに値がある場合は、同期された実装を使用して、最初の Node オブジェクトがロックするロック フラグとして使用されます。

public class HashMapDemo {
    
    

    /*
       HashMap是线程不安全的,不能并发操作的
       ConcurrentModificationException  并发修改异常   遍历集合,并删除集合中的数据

       Hashtable 是线程安全的 public synchronized V put(K key, V value)-->独占锁
            锁直接加到了put方法上,锁粒度比较大,效率比较低
            用在低并发情况下可以

       Map<String,Integer> map = Collections.synchronizedMap(new HashMap<>());
       ConcurrentHashMap
     */
    public static void main(String[] args) {
    
    

        ConcurrentHashMap<String,Integer> map = new ConcurrentHashMap<>();
        //模拟多个线程对其操作
        for (int i = 0; i < 20; i++) {
    
    
                 new Thread(
                     ()->{
    
    
                       map.put(Thread.currentThread().getName(), new Random().nextInt());
                         System.out.println(map);
                     }
                 ).start();
        }

    }
}

CopyOnWriteArrayList

読み取りと書き込みは完全に分離されており、読み取り操作にはロックが必要なく、読み取りはデータに影響を与えません。

書き込み操作はロックされており、書き込み操作は読み取り操作には影響しません。2 つのスレッドを同時に追加すると、それらは相互に排他的になります。

追加するときは、まず元の配列のコピーを作成します。

次に、読み取り操作に影響を与えずにデータをコピーに追加します。

最後に元の配列をコピーで置き換えます

CopyOnWriteArraySet

重複データを許可しないものです

基礎となる実装は CopyOnWriteArrayList であり、重複したデータを保存できません。

補助クラスCountDownLatch

スレッドを実行する前に、他のスレッドの実行が完了するまで待機させます。

デクリメントするスレッドカウンタと同等

最初に数値を設定し、スレッドが終了したら 0 になるまで 1 つずつ減らしていき、カウンターを閉じるとスレッドが実行されます。

[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムが存在する可能性があります。画像を保存して直接アップロードすることをお勧めします (img-wS5P0aFG-1642418593327) (C:\Users\Cloud\AppData\Roaming\Typora\) typora-user-images\ 1642401770485.png)]

補助クラスCyclicBarrier

スレッドのグループがバリアに到達したときにブロックされるようにします。最後のスレッドがバリアに到達するまでバリアは開きません。

加算カウンターで、スレッド数が規定数に達すると扉が開いて解放されます。

Javaでロックする

ロックの名詞は数多くありますが、これらの分類はすべてがロックを指すわけではなく、ロックの特性を指すものや、ロックのデザインを指すものもあります。

ロックの状態について言及しているものもありますが、以下にまとめた内容は各ロックの名詞についての一定の説明です。

楽観的ロック/悲観的ロック

楽観的ロック:ロックがないことを意味し、同時変更は問題ないと考えられています。たとえば、CAS メカニズムはロックなしの方法で実装されるように設計されており、多くの読み取り操作に適しています。

悲観的ロック: 同時操作で問題が発生すると考えられており、安全性を確保するためにロックが必要です。多くの書き込み操作に適しています。

リエントラントロック

リエントラントロック

デッドロックはある程度回避できる

同期されたメソッドが、同じロックを使用する別のメソッドを呼び出すとき

外側のメソッドにリリースがない場合でも、別の同期メソッドを入力できます。

リエントラント ロックと同期は両方ともリエントラント ロックです

例: setA() メソッドと setB() メソッドは同じロックを使用します。setA メソッドに入った後、ロックが取得され、setB メソッドが呼び出されます。ロックがリエントラントでない場合、setA() ではロックは解放されません。 setB() メソッド 現在のスレッドでは実行されませんが、リエントラントロックであれば、デッドロックを引き起こすことなくスムーズに setB() メソッドを実行できます。

[外部リンク画像の転送に失敗しました。ソース サイトにはリーチ防止メカニズムが存在する可能性があります。画像を保存して直接アップロードすることをお勧めします (img-p1ee1woE-1642418593330) (C:\Users\Cloud\AppData\Roaming\Typora\) typora-user-images\ 1642417471732.png)]

読み取り書き込みロック (読み取り書き込みロック)

これは特殊なロックの実装であり、読み取りと書き込みは 2 つのロックであり、別々に使用できます。

セグメントロック

これはロックのアイデアであり、実際のロックの実装ではなく、セグメント化されたロックを使用してロックの粒度を減らし、効率を向上させます。

スピンロック

ロック実装ではなく、スピン(ループリトライ)を利用して実行権の獲得を試み、スレッドをブロック状態にさせないため、ロック時間が短い場合に適しています。

CASはスピンロックに基づいて実装されています

共有ロック

複数のスレッドで共有できるロック

ReadWriteLock の読み取りロックは共有され、複数のスレッドが同時にデータを読み取ることができます。

排他ロック

ミューテックス ロックとも呼ばれ、一度に 1 つのスレッドのみがロックを取得できます。

リエントラント ロック、同期、ReadWriteLock の書き込みロックは排他的ロックです

ReadWriteLock の実装では、同期キューを使用します。たとえば、読み取りスレッドはリソースを取得し、標準状態を使用済みに設定し、他の書き込みスレッドをキューに追加して待機します。

AQS(AbstractQueuedSynchronizer)

待機中のスレッドがキューに入るようにキューを維持します。

フェアロック

スレッドの待機リストを維持し、スレッドを一度に実行します。

リエントラント ロックはデフォルトでは不公平ですが、作成時に構築メソッドによって公平なロックか不公平なロックかを指定できます。

不当なロック

キューはありません。ロックが解放されると、スレッドはプリエンプトを開始します。実行権を獲得した人が最初に実行されます。

ロック状態

ロックなし/バイアスロック/軽量ロック/重量ロック

バイアスされたロック: 1 つのスレッドだけが常にロックを取得していることを指します。これにより、ロックの取得が容易になります。

軽量ロック: ロックがバイアスされたロックで、別のスレッドによってアクセスされると、バイアスされたロックは軽量ロックにアップグレードされます。軽量ロックの場合、待機中のスレッドはブロッキング状態にならず、スピン モードを使用します。試してみてください。効率を向上させるためにロックを再度取得します。

重量ロック: ロック状態が軽量ロックの場合、一部のスレッドのスピンが多すぎる場合、またはスレッドアクセス数が多い場合、ロック状態は重量ロックにアップグレードされます。ロックは自動的に回転しなくなり、ブロック状態になります

リエントラントロック

これはクラスであり、コード ブロックを変更してロックを表示し、手動で追加し、手動で解放することしかできません。

これは、CAS+AQS を使用したクラスレベルの制御であり、再入可能なロックであり、公正なロックである場合もそうでない場合もあります。

ロック状態はクラス内で維持されます。スレッドがそれをプリエンプトすると、状態は 1 に変更され、他のスレッドはキューに入り、ロックが解放されるのを待ちます (公平なロックの場合)。次に、ヘッド ノードを起動し、ロックの取得を開始します。

同期した

それはリエントラントロックであり、不公平なロックです。

コードブロックやメソッドを変更できるキーワードです。

これは暗黙的なロックであり、ロックを自動的に取得および解放できます。

synchronized は、命令レベルでロックとロックの解放を実装します。

モニターへのエントリーがある +1 オブジェクトのヘッドロック フラグが使用されている

タスクを実行する

モニタを終了します -1 0 に等しい場合、オブジェクトのヘッド ロック マークはロックなしに変更されます。

おすすめ

転載: blog.csdn.net/crraxx/article/details/122546568