Java同時実行データ構造-同時リスト



Java Concurrency Data Structure Concurrent List



序文


並列プログラムとシリアルプログラムの特性が異なるため、シリアルプログラムに適した一部のデータ構造は、並行環境では直接機能しない場合があります。これは、これらのデータ構造がスレッドセーフではないため、同時環境についての学習に重点を置いているためです。リスト、セット、およびマップの一般的なセキュリティデータ構造は何ですか?この記事では、同時リストの学習内容を記録します。

セキュアリストの実装


1.ベクトル
2.Collections.synchronizedList(リストリスト);
3.CopyOnWriteArrayList(主にそれを参照)



CopyOnWriteArrayListの同時リスト


VectorまたはCopyOnWriteArrayListは、2つのスレッドセーフなリスト実装です。マルチスレッド環境でArrayListを使用しないようにする必要があるため、ArrayListはスレッドセーフではありません。何らかの理由で使用する必要がある場合は、次のパッケージも使用する必要があります。

List selfList = Collections.synchronizedList(new ArrayList())

CopyOnWriteArrayListの内部実装はVectorとは異なります。定義からわかるように、Copy-On-WriteはCopyOnWriteArrayListの実装メカニズムです。つまり、オブジェクトが書き込み操作を実行する場合、オブジェクトが読み取り操作である場合はオブジェクトがコピーされ、構造が直接返され、操作中に同期は実行されません。
CopyOnWriteArrayListは、オブジェクトの不変性をうまく利用します。オブジェクトが書き込まれる前は、オブジェクトは変更されていないため、ロックは必要ありません。オブジェクトを変更しようとするときは、常にオブジェクトのコピーを取得し、そのコピーを変更して、最後にコピーを書き戻します。
この実装の中心的なアイデアは、ロックの競合を実現することです。これにより、高い同時実行性での読み取りパフォーマンスが向上しますが、書き込みパフォーマンスはある程度犠牲になります。
CopyOnWriteArrayListのソースコードをさらに詳しく調べます。 get()メソッドの実装:



public E get(int index) { return elementAt(getArray(), index) } static E elementAt(Object[] a, int index) { return (E) a[index] }

スレッドセーフな実装として、CopyOnWriteArrayListのget()メソッドにはロック操作がないことがわかります。読むときにロックする必要はありません。読み取り時に複数のスレッドがArrayListにデータを追加している場合でも、読み取りは読み取られます。古いArrayListは書き込み時にロックされないため、古いデータ。そして、ベクトルgetの実装を比較します。

public synchronized E get(int index) { if (index >= elementCount) throw new ArrayIndexOutOfBoundsException(index) return elementData(index) } E elementData(int index) { return (E) elementData[index] }

ベクトルは同期キーワードを使用し、オブジェクトを乗算する前に、すべてのget()操作をフェッチする必要があります。同時実行性が高い状況では、大量のロック競合がシステムパフォーマンスを低下させる可能性があります。

そのadd()メソッドの実装:



final transient Object lock = new Object() public boolean add(E e) { synchronized (lock) { Object[] es = getArray() int len = es.length es = Arrays.copyOf(es, len + 1) es[len] = e setArray(es) return true } }

追加するときにロックする必要があることがわかります。そうしないと、N個のマルチスレッドがN個のコピーをコピーするため、書き込みのパフォーマンスは明らかに良くありません。

他にもremote、clear、clone、containsなどがあり、ArrayListの使用法は基本的に同じです。興味がある人は、ArrayListの違いと比較して、自分でそれを見ることができます。

CopyOnWriteArrayListの読み取りと書き込みの実装も比較的簡単です。そのアプリケーションシナリオを見てみましょう。

CopyOnWriteArrayListのアプリケーションシナリオ

このフィルムのテーマは同時セキュリティリストであるため、主に同時マルチスレッドがリストに対して読み取りおよび書き込み操作を行うシナリオで使用されます。たとえば、トラフィック監視システムがあります。その1つは、今日のアクセスIPをカウントすることです。これは、同時に複数のアクセスが存在する可能性があるため、明らかに同時シナリオです。正確な統計を確保するために、CopyOnWriteArrayListの使用を検討できます。 IPデータの保存:

/** * @Author: root@xxxxx * @Date: 2019-4-29 0029 23:04 * @Description: Traffic Platform IP Statistics */ public class DataMonitorService { /** * Traffic statistics, IP monitoring list */ private static CopyOnWriteArrayList MONITOR_IP = new CopyOnWriteArrayList() /** * Is it under monitoring? */ public static boolean isMonitor(String ip){ return MONITOR_IP.contains(ip) ? true : false } /** * Get the latest ip */ public static String lastIp(){ return MONITOR_IP.get(MONITOR_IP.size()-1) } /** * Add to watch list */ public static void addMonitor(String ip){ if (!isMonitor(ip)) { MONITOR_IP.add(ip) } } }

コードは非常に単純ですが、注意深いクラスメートは、書き込み時にロックされていると言ったことに気付くかもしれません。パフォーマンスはそれほど悪くはありません。この例のトラフィック監視表示は、同時シーン+リアルタイムの読み取りと書き込みです。シーン、これは適していません。うーん~~~、はい、それはこのようなものです、その欠点であるパフォーマンスの問題がありますが、それはあなたのトラフィック統計が安全であることを保証することができます。

総括する


つまり、要素を追加する場合、CopyOnWriteArrayListは常にコピーしているため、パフォーマンスはArrayListよりもはるかに劣りますが、スレッドセーフであるため、いつ使用するかはビジネスシナリオによって異なります。

RelaxHeart-Tecブログ:私のその他の記事