SynchronizedList と Vector の間に違いはありますか? Java API がスレッドセーフな List のこれら 2 つの実装を提供するのはなぜですか?

Vector は、java.util パッケージ内のクラスです。SynchronizedList は、java.util.Collections の静的な内部クラスです。

マルチスレッドのシナリオでは、Vector クラスを直接使用するか、Collections.synchronizedList(List list) メソッドを使用してスレッドセーフなリストを返すことができます。

では、SynchronizedList と Vector には何か違いがあるのでしょうか? なぜ Java API はこれら 2 つのスレッドセーフな List 実装を提供するのでしょうか?

まず、Vector と Arraylist は両方とも List のサブクラスであり、それらの基礎となる実装は同じであることがわかります。list1したがって、次の 2 つの合計の差は次のとおりですlist2

List<String> list = new ArrayList<String>();
List list2 =  Collections.synchronizedList(list);
Vector<String> list1 = new Vector<String>();

まず、いくつかの重要な方法を比較します。

1.1 追加メソッド

ベクターの実装:

public void add(int index, E element) {
    insertElementAt(element, index);
}

public synchronized void insertElementAt(E obj, int index) {
    modCount++;
    if (index > elementCount) {
        throw new ArrayIndexOutOfBoundsException(index
                                                 + " > " + elementCount);
    }
    ensureCapacityHelper(elementCount + 1);
    System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
    elementData[index] = obj;
    elementCount++;
}

private void ensureCapacityHelper(int minCapacity) {
    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

synchronizedListの実装:

public void add(int index, E element) {
   synchronized (mutex) {
       list.add(index, element);
   }
}

ここでは、ArrayList の add() メソッドが同期コード ブロックを使用して呼び出されます。ArrayListのaddメソッドの内容は以下のとおりです。

public void add(int index, E element) {
    rangeCheckForAdd(index);
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    System.arraycopy(elementData, index, elementData, index + 1,
                     size - index);
    elementData[index] = element;
    size++;
}
private void rangeCheckForAdd(int index) {
    if (index > size || index < 0)
        throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
private void ensureCapacityInternal(int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    ensureExplicitCapacity(minCapacity);
}

上記の 2 つのコードには 2 つの違いがあります。1. Vector は同期メソッドを使用して実装され、synchronizedList は同期コード ブロックを使用して実装されます。2. 両者は配列の容量を拡張する方法が異なります(容量拡張における両者の加算方法の違いは、ArrayListとVectorの違いでもあります)。

1.2 削除メソッド

synchronizedListの実装:

public E remove(int index) {
    synchronized (mutex) {return list.remove(index);}
}

ArrayListクラスのremoveメソッドは以下のとおりです。

public E remove(int index) {
    rangeCheck(index);

    modCount++;
    E oldValue = elementData(index);

    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    elementData[--size] = null; // clear to let GC do its work

    return oldValue;
}

ベクターの実装:

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;
    }

Remove メソッドでは、一方が同期メソッドを使用し、もう一方が同期コード ブロックを使用することを除いて、ほとんど違いがないことがわかりました。

他のメソッドを比較すると、SynchronizedList に実装されているメソッドは、ほとんどすべて同期コード ブロックを使用して List をラップするメソッドであることがわかりました。List が ArrayList の場合、SynchronizedList と Vector の明らかな違いは、一方は同期コード ブロックを使用し、もう一方は同期メソッドを使用することです。

3. 差異分析

データ増加の違い

内部実装メカニズムから、ArrayList と Vector は両方とも配列 (Array) を使用してコレクション内のオブジェクトを制御します。これら 2 つの型に要素を追加するとき、要素の数が内部配列の現在の長さを超える場合、それらはすべて内部配列の長さを拡張する必要があります。デフォルトでは、Vector は元の配列の長さを自動的に 2 倍にし、ArrayList は元の 50% なので、実際に必要なスペースよりも常に多くのスペースを占めるコレクションが作成されます。したがって、コレクションに大量のデータを保存したい場合は、コレクションの初期化サイズを設定することで不要なリソースのオーバーヘッドを回避できるため、Vector を使用するといくつかの利点があります。

同期コードブロックと同期メソッドの違い

1. 同期コード ブロックの範囲は同期方法の範囲よりも小さい場合がありますが、一般的に言えば、ロックの範囲はパフォーマンスに反比例します。

2. 同期ブロックはロックの範囲をより正確に制御できます (ロックの範囲はロックの取得から解放までの時間です)。また、同期メソッドのロックの範囲はメソッド全体です。 。

3. 同期コード ブロックはロックするオブジェクトを選択できますが、静的メソッドはこのオブジェクトのみをロックできます。

SynchronizedList は ArrayList のメソッドを同期コードブロックでラップしているだけであり、ArrayList と Vector の同名のメソッドのメソッド本体の内容に大きな違いはないため、ロックの範囲とロックの範囲に違いはありません。ロックされたオブジェクトの違いに関して言えば、SynchronizedList の同期コード ブロックはミューテックス オブジェクトをロックし、Vector は this オブジェクトをロックします。では、ミューテックスオブジェクトとは何でしょうか? 実際、SynchronizedList にはオブジェクトを渡すことができるコンストラクターがあり、呼び出し時にオブジェクトが渡されると、ユーザーによって渡されたオブジェクトはロックされます。指定しない場合、このオブジェクトもロックされます。

したがって、これまでのところ、SynchronizedList と Vector には次の 2 つの違いがあります。 1. add メソッドが使用される場合、それらの拡張メカニズムが異なります。2.SynchronizedListはロックされているオブジェクトを指定できます。

ただし、すべてのものには「しかし」があります。SynchronizedList に実装されたクラスは、すべてが同期された同期コード ブロックを使用するわけではありません。このうち、listIterator と listIterator(int Index) は同期しません。ただし、Vector はこのメソッドにメソッド ロックを追加します。したがって、トラバーサルに SynchronizedList を使用する場合は、手動でロックする必要があります。

でも、でも、それなら、でも。

前の比較は、ArrayList から SynchronizedList への変換に基づいています。したがって、LinkedList をスレッドセーフにしたい場合、または途中での挿入と削除に便利な同期されたリンク リストが必要な場合は、基礎となるデータ構造を変更せずに、既存の LinkedList を SynchronizedList に直接変換できます。そして、これは Vector では実行できないことです。Vector の基礎となる構造は配列を使用して実装されており、配列は変更できないためです。

結局のところ、SynchronizedList と Vector の主な違いは次のとおりです。1. SynchronizedList には優れた拡張機能と互換性機能があります。彼はすべての List サブクラスをスレッドセーフなクラスに変換できます。 2. SynchronizedList を使用する場合、トラバース時に手動同期が必要です3.SynchronizedListはロックされているオブジェクトを指定できます。

おすすめ

転載: blog.csdn.net/zy_dreamer/article/details/132350309