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はロックされているオブジェクトを指定できます。