インタビュアーは、スレッドセーフでなければならない私(このようなベクターなど)すべての操作の同期コンテナを尋ねましたか?私は無知です!

神の道へのJavaエンジニアのGitHubの7.7kスター、それについて知って来ないのですか?

神の道へのGitHubのJavaエンジニアの7.7kスターは、本当にそれを見ませんか?

神へのJavaエンジニアの道のGitHub 7.7kスターは、実際にそれについて知っていないと判断しますか?

スレッドセーフなプログラミングを容易にするために、スレッドセーフなクラスやような同時ツールの数を提供するJava:同期コンテナ、同時コンテナ、キューを遮断します。

スレッドセーフなコンテナが行う最も一般的なコンテナはベクトルとハッシュテーブルを同期して、すべての操作を同期されていますか?

この問題は、この問題では、深さを見に簡単に見落とさ問題を分析するために、この論文については考えていないわかりません。

Java同期コンテナ

Javaでは、同期クラス2を含むコンテナ:

  • 1、ベクトル、スタック、ハッシュテーブル
  • クラスを作成するコレクションクラスで提供2、staticファクトリメソッド

比較的単純な例を取るためにこの記事Vecotrは、のを見て、いくつかの重要な方法のベクトルのソースを見てみましょう:

public synchronized boolean add(E e) {
    modCount++;
    ensureCapacityHelper(elementCount + 1);
    elementData[elementCount++] = e;
    return true;
}

public synchronized E remove(int index) {
    modCount++;
    if (index >= elementCount)
        throw new ArrayIndexOutOfBoundsException(index);
    E oldValue = elementData(index);

    int numMoved = elementCount - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    elementData[--elementCount] = null; // Let gc do its work

    return oldValue;
}

public synchronized E get(int index) {
    if (index >= elementCount)
        throw new ArrayIndexOutOfBoundsException(index);

    return elementData(index);
}
复制代码

あなたは、私たちが安全にマルチスレッドのシナリオでのみこれらのメソッドを使用することができることを意味し、同期などの容器ベクターのすべてのパブリックメソッドがすべて同期していることを見ることができ、これらのメソッド自身実際にスレッドセーフので。

しかし、上記の文は、より重要な言葉があることに注意してください。一人で

そのため、コンテナを同期するすべての方法は、ロックを追加したが、これらの血管の複合操作がスレッドの安全性を保証することはできませんにもかかわらず。クライアントは、アクティブなロックによって保証される必要があります。

簡単な例では、我々は次のように定義されたベクトル法の最後の要素を削除するには:

public Object deleteLast(Vector v){
    int lastIndex  = v.size()-1;
    v.remove(lastIndex);
}
复制代码

上記の方法は、サイズ(を含む、複雑な方法である)および()メソッド)(削除一見それは思われなかった問題は、それがサイズ()メソッドであるか否かを削除スレッドセーフであり、次いで、全体の方法はまた、deleteLastべきスレッドセーフ。

しかし、複数のスレッドがメソッドを削除し、このメソッドを呼び出した場合、プロセスは、ArrayIndexOutOfBoundsExceptionがをスローすることがあります。

Exception in thread "Thread-1" java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 879
    at java.util.Vector.remove(Vector.java:834)
    at com.hollis.Test.deleteLast(EncodeTest.java:40)
    at com.hollis.Test$2.run(EncodeTest.java:28)
    at java.lang.Thread.run(Thread.java:748)
复制代码

私たちは、ソースコードを削除し、我々は結果を分析することができ、上記の投稿:インデックス> =し、elementCount時間は、ArrayIndexOutOfBoundsExceptionががスローされます場合は、それは、現在のインデックスの値がもはや有効であるとき、これは例外をスローしませんされている場合。

2によって糸10は、インデックス値インデックス()を得る場合removeLast方法は、同時に実行される複数のスレッドが存在する可能性があるため、削除することによって()要素のインデックス位置を削除する前に、スレッドインデックス位置の値を除去します、その後、実装内のスレッドは例外をスローします。

同様の問題を回避するには、ロックしようとすることができます。

public void deleteLast() {
    synchronized (v) {
        int index = v.size() - 1;
        v.remove(index);
    }
}
复制代码

我々はdeleteLastとして、ロックされたVの行為は、あなたが同じ時間を保証することができ、他のスレッドは、Vの要素を削除しません。

次のコードは、複数のスレッドを実行した場合また、特別な注意が必要です。

for (int i = 0; i < v.size(); i++) {
    v.remove(i);
}
复制代码

そのため、削除を含みベクターで動作し、同時に別のスレッドで、安全性の問題を通すことも可能です。同期コンテナを使用しているとき、それは同時に除去を行う複数のスレッドに来る場合そのため、我々は必要がロックダウンするかどうかを検討しなければなりません。

同期コンテナの質問

私は前に述べたときは、同期コンテナは直接遅延の操作をスレッドセーフではなく、その場合には、アクティブなロックモードによって達成されなければならない、複雑でスレッドセーフな動作を保証することはできません。

そして、するとき、さらに、その簡単に複数のスレッドにつながった、すべてのメソッドは、ロックに追加された同期には、GETなど、異なっても操作のために、同じコンテナ、唯一のシーケンシャルアクセスにアクセスするだけでなく、ラインアップキューおよび実行するために追加します。これは、大幅に並行性のコンテナを低減します。

コンカレント・コンテナー

以前初めJava5から、言及した同時実行性の問題同期コンテナの程度が低いために、サポートやコレクションへの効率的な同時アクセスの多くを提供しjava.util.concurentパッケージの下、我々はコンカレント・コンテナーを呼び出します。

前述の同期コンテナの動作を組み合わせた質問については、より一般的に地図に発生したので、ConcurrentHashMapの中に、共通の複合操作のサポートを追加することは、そのような「あなたは追加しない場合」のように:putIfAbsent()、交換してください:置き換えます()。これらの2つの操作が、アトミック操作されているスレッドの安全性を保証することができます。

また、契約およびCopyOnWriteArrayListととCopyOnWriteArraySetは2コピー・オン・ライト実現しています。

コピーオンライトコピーオンライトのコンテナコンテナを。あなたは要素を追加した後で人気の理解は、私たちがコンテナに要素を追加する場合、直接現在のコンテナに追加しますが、最初に現在のコンテナをコピーし、新しいコンテナをコピーし、新しいコンテナ要素を追加していないということです、その後、元の容器の参照は、新しいコンテナを指します。

追加/メソッドを削除でCopyOnWriteArrayListとは、読んでメソッドがロックされていないが、このようなロックとして記述する必要があります。

これの利点は、我々がリードデータが最新でない場合も当然の同時コピーオンライトのコンテナを、読み取ることができるということです。コピー・オン・ライトのアイデアは、データの究極の一貫性、遅延によって、ポリシー更新のない強い一貫性を達成することであるため。

しかし、代わりにベクトルCopyOnWriteArrayListとの同期コンテナの動作を組み合わせたスレッドの安全性の問題を解決しません。

概要

この記事では、同期コンテナとコンカレント・コンテナーを説明しています。

同期は、コンテナのロックスレッドセーフで達成され、唯一のスレッドの安全性の複雑な操作を保証することはできません、個々の操作は、スレッドセーフであることを確認することができます。そして、お互いの容器に同期して、読み取りおよび書き込み動作の間詰まらせます。

Java 5のコンカレント・コンテナー、提供主な場所で容器を同期するために使用されます。より良い並行処理。そして、スレッドセーフConcurrentHashMapの複合動作を定義しています。

マルチスレッドのシナリオでは、コンカレント・コンテナーを使用する場合は、操作を組み合わせ、安全性の問題をスレッドに注意を払う必要があります。必要な場合には、イニシアチブロックを取ること。

同時シナリオでは、直接提供コンテナクラスjava.util.concurentパッケージを使用することが推奨され、必要な複合操作あれば、いくつかの方法は、それ自体が提供複合容器を使用することが推奨されます。

おすすめ

転載: juejin.im/post/5d633d25f265da03bc1284da