sql >> データベース >  >> RDS >> Database

Javaでの並行コレクションAPIの概要

    コンカレントコレクションAPIは、JavaコレクションAPIとは別に、同期されたマルチスレッドアクセス用に特別に設計および最適化されたコレクションAPIのセットです。これらはjava.util.concurrentの下にグループ化されています パッケージ。この記事では、概要を説明し、適切なシナリオ例を使用してその使用法を紹介します。

    概要

    Javaは、当初からマルチスレッドと並行性をサポートしてきました。スレッドは、 Runnableを実装することによって作成されます。 インターフェイスまたはスレッドの拡張 クラス。同期は、同期と呼ばれるキーワードによって実現されます。 。 Javaは、スレッド間の通信のメカニズムも提供します。これは、 notify()の助けを借りて実現されます およびwait() オブジェクトの一部であるメソッド クラス。これらの革新的なマルチスレッド技術は、Javaの優れた機能の一部ですが、すぐに使用できる集中的なマルチスレッド機能を必要とするプログラマーのニーズを提供するには、やや不十分です。これは、並行プログラムには、スレッドを作成して基本的な操作を実行できるだけでなく、それ以上のものが必要なためです。スレッドプール、実行マネージャー、セマフォなど、多くの高レベルの機能が必要です。

    既存のコレクションフレームワーク

    Javaにはすでに本格的なコレクションフレームワークがあります。コレクションは、その機能に非常に優れており、Javaスレッドアプリケーションでも使用できます。また、同期と呼ばれるキーワードがあります 、スレッドセーフにするため。一見、マルチスレッドで使用するのは良いことのように思えるかもしれませんが、スレッドセーフを実現する方法が、同時実装の主なボトルネックです。明示的な同期は別として、それらは最初から並行実装のパラダイムの下で設計されていません。これらのコレクションの同期は、コレクションの状態へのすべてのアクセスをシリアル化することによって実現されます。これは、ある程度の並行性があるかもしれませんが、基礎となるシリアル化された処理のために、実際には反対の原理で動作することを意味します。シリアル化は、特に複数のスレッドがコレクション全体のロックをめぐって競合する場合、パフォーマンスに大きな負担をかけます。

    新しいコレクションAPI

    並行コレクションAPIは、バージョン5からJavaに追加されたものであり、 java.util.concurrentと呼ばれるパッケージの一部です。 。これらは既存のコレクションAPIを改良したものであり、複数のスレッドからの同時アクセス用に設計されています。たとえば、 ConcurrentHashMap 同期されたハッシュベースのマップを使用する場合に必要なクラスです。 実装。同様に、トラバーサルドミナントでスレッドセーフなリストが必要な場合 、実際には CopyOnWriterArrayListを使用できます クラス。新しいConcurrentMap インターフェイスは、 putIfPresent など、単一のメソッドで多数の複合アクションを提供します 、 computeIfPresent 交換マージ 、 等々。新しい並行収集フレームワーク内にあるそのようなクラスはたくさんあります。いくつか例を挙げると、 ArrayBlockingQueue ConcurrentLinkedDeque ConcurrentLinkedQueue ConcurrentSkipListMap ConcurrentSkipListSet CopyOnWriteArraySet DelayQueue LinkedBlockingDeque LinkedBlockingQueue LinkedTransferQueue PriorityBlockingQueue SynchronousQueue 、その他。

    キュー

    キューなどのコレクションタイプ およびBlockingQueue 、要素を一時的に保持するために使用できます。待機中は、処理のためにFIFO方式で取得されます。 ConcurrentLinkQueue 一方、は、リンクされたノードに基づく無制限のスレッドセーフキューとして実装された従来のFIFOキューです。 PriorityBlockingQueue は、非同時の PriorityQueueと同じ順序付け基準を使用する無制限のブロッキングキューです。 ブロッキング検索操作を提供します。

    マップ

    古いコレクションクラスでは、同期が適用されると、各操作の間ロックが保持されます。 getなどの操作があります HashMapのメソッド または含む リストのメソッド 、呼び出されたときに舞台裏で複雑な計算が含まれます。たとえば、リスト内の特定の要素を見つけるために、 equalsを自動的に呼び出します。 方法。この方法では、リストの各要素を比較するために特定の計算が必要です。タスクの完了には長い時間がかかる場合があります。これは、ハッシュベースのコレクションではさらに悪化します。ハッシュマップ内の要素が不均一に分散している場合、長いリストをトラバースしてequalsを呼び出すと、非常に長い時間がかかる可能性があります。これは、アプリケーションの全体的なパフォーマンスに影響を与える可能性があるため、問題です。

    HashMapとは異なり 、 ConcurrentHashMap まったく異なる戦略を使用します。同期されたすべてのメソッドに共通のロックを提供する代わりに、ロックストリッピングと呼ばれる手法を使用します。 。これは、並行性とスケーラビリティの両方にとってより優れたソリューションです。ロックストリッピングは、個別のバケットに個別のロックを使用します。その結果、スレッドの競合は基になるデータ構造から切り離され、代わりにバケットに課されます。たとえば、ConcurrentHashMapの実装では、16個のロックの配列を使用します。各ロックはハッシュバケットの1/16を保護します。バケットNはロックNmod16によって保護されています…これにより、特定のロックの需要が約16分の1に減少します。 ConcurrentHashMap は、この手法によるものです。 デフォルトで少なくとも16の同時ライターをサポートし、オンデマンドでさらに多くのライターに対応できます。

    CopyOnWriterArrayList

    これは、同期されたリストの優れた代替手段です。 反復中にロックメカニズムを適用する必要はありません。イテレータは、反復の開始時にバッキング配列への参照を保持し、それを変更しません。したがって、配列の内容を取得するには、簡単な同期が必要です。複数のスレッドが互いに干渉することなくコレクションにアクセスできます。複数のスレッドからの変更でさえ、競合は発生しません。 CopyOnWriterSet と呼ばれる、この配列リストの対応するセットがあります。 、同期された Setの代わりに使用できます 並行性の必要性について。

    簡単な例

    コンカレントコレクションには多くのクラスがあります。それらの使用は、古いコレクションフレームワークに精通している人にとってはそれほど難しくありません。完全を期すために、Javaプログラミングでの使用法を垣間見るための例を次に示します。

    package org.mano.example;
    import java.util.Random;
    import java.util.concurrent.BlockingQueue;
    import java.util.concurrent.LinkedBlockingQueue;
    public class ProducerConsumerDemo {
       static BlockingQueue<Integer> queue = new
          LinkedBlockingQueue<>(5);
       public static void main(String[] args) throws
             InterruptedException {
          int noOfProducers = 7;
          int noOfConsumers = 9;
          for (inti = 0; i < noOfProducers; i++) {
             new Thread(new Producer(), "PRODUCER").start();
          }
          for (int i = 0; i < noOfConsumers; i++) {
             new Thread(new Consumer(), "CONSUMER").start();
          }
          System.exit(0);
       }
       static class Producer implements Runnable {
          Random random = new Random();
          public void run() {
             try {
                int num = random.nextInt(100);
                queue.put(num);
                System.out.println("Produced: " + num
                   + " Queue size : "+ queue.size());
                Thread.sleep(100);
             } catch (InterruptedException ex) {
                System.out.println("Producer is interrupted.");
             }
          }
       }
       static class Consumer implements Runnable {
          public void run() {
             try {
                System.out.println("Consumed: " + queue.take()
                   + " Queue size : "+ queue.size());
                Thread.sleep(100);
             } catch (InterruptedException ex) {
                System.out.println("Consumer is interrupted.");
             }
          }
       }
    }
    

    結論

    おそらく、並行収集クラスを使用する最大の利点は、それらのスケーラビリティと低リスクです。 Javaの並行収集APIは、並行操作を処理するために特別に設計された一連のクラスを提供します。これらのクラスは、Java Collection Frameworkの代替であり、並行性の追加サポートを除いて、同様の機能を提供します。したがって、Javaコレクションフレームワークについてすでに知っているプログラマーの学習曲線はほぼ平坦です。クラスはパッケージjava.util.concurrentで定義されています 。ここでは、開始するための概要を説明し、必要に応じてコレクションAPIを使用するようにしました。

    参照

    • JavaAPIドキュメント
    • ゲッツ、ブライアン、ティム・パイエルス。 実際のJava同時実行性 。ピアソン、2013年。

    1. SELECTステートメントでのNOLOCKヒントの効果

    2. ドロップダウンを使用した場合、SQLインジェクションを防ぐ必要がありますか?

    3. SQL Server 2016:ビューデザイナー

    4. SQLエスケープを使用した動的mysqlクエリは、プリペアドステートメントと同じくらい安全ですか?