Is there any difference between SynchronizedList and Vector? Why does java api provide these two implementations of thread-safe List?

Vector is a class in the java.util package. SynchronizedList is a static inner class in java.util.Collections.

In a multi-threaded scenario, the Vector class can be used directly, or the Collections.synchronizedList(List list) method can be used to return a thread-safe List.

So, is there any difference between SynchronizedList and Vector? Why does java api provide these two thread-safe implementations of List?

First of all, we know that both Vector and Arraylist are subclasses of List, and their underlying implementations are the same. So here is the difference between the following two list1sums list2:

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

First, compare several important methods.

1.1 add method

Implementation of Vector:

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

Implementation of synchronizedList:

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

Here, the add() method of ArrayList is called using a synchronous code block. The content of the add method of ArrayList is as follows:

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

There are two differences found in the above two pieces of code: 1. Vector is implemented using a synchronization method, and synchronizedList is implemented using a synchronization code block. 2. The ways to expand the array capacity of the two are different (the difference between the add method of the two in terms of capacity expansion is also the difference between ArrayList and Vector.)

1.2 remove method

Implementation of synchronizedList:

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

The remove method of the ArrayList class is as follows:

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

Implementation of Vector:

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

From the remove method, we found that there is almost no difference except that one uses a synchronous method and the other uses a synchronous code block.

By comparing other methods, we found that the methods implemented in SynchronizedList are almost all methods that use synchronized code blocks to wrap List. If the List is an ArrayList, then an obvious difference between SynchronizedList and Vector is that one uses a synchronization code block and the other uses a synchronization method.

3. Difference Analysis

Data growth difference

From the internal implementation mechanism, both ArrayList and Vector use arrays (Array) to control the objects in the collection. When you add elements to these two types, if the number of elements exceeds the current length of the internal array, they all need to expand the length of the internal array. By default, Vector automatically doubles the original array length, and ArrayList is the original 50%, so you end up with a collection that always takes up more space than you actually need. So if you want to save a lot of data in the collection, then using Vector has some advantages, because you can avoid unnecessary resource overhead by setting the initialization size of the collection.

The difference between a synchronized code block and a synchronized method

1. The scope of the synchronization code block may be smaller than that of the synchronization method. Generally speaking, the scope of the lock is inversely proportional to the performance.

2. The synchronization block can control the scope of the lock more precisely (the scope of the lock is the time from when the lock is acquired to when it is released), and the scope of the lock of the synchronization method is the entire method.

3. The synchronization code block can choose which object to lock, but the static method can only lock the this object.

Because SynchronizedList just wraps the method of ArrayList with synchronous code block, and the method body content of the method with the same name in ArrayList and Vector is not much different, so there is no difference between the locking scope and the scope of the lock. In terms of the difference between locked objects, the synchronization code block of SynchronizedList locks the mutex object, and the Vector locks the this object. So what is the mutex object? In fact, SynchronizedList has a constructor that can pass in an Object. If an object is passed in when it is called, then the object passed in by the user is locked. If not specified, the this object is also locked.

Therefore, there are two differences between SynchronizedList and Vector so far: 1. If the add method is used, their expansion mechanisms are different. 2.SynchronizedList can specify the locked object.

However, everything has a but. The classes implemented in SynchronizedList do not all use synchronized synchronization code blocks. Among them, listIterator and listIterator(int index) are not synchronized. But Vector adds a method lock to this method. Therefore, when using SynchronizedList for traversal, you need to manually lock.

But, but then there is but.

The previous comparisons are based on our conversion of ArrayList to SynchronizedList. So if we want to make LinkedList thread-safe, or I want a synchronized linked list that is convenient for insertion and deletion in the middle, then I can directly convert the existing LinkedList into a SynchronizedList without changing its underlying data structure. And this is something that Vector cannot do, because its underlying structure is implemented using arrays, which cannot be changed.

So, in the end, the main difference between SynchronizedList and Vector: 1. SynchronizedList has good expansion and compatibility functions. He can convert all List subclasses into thread-safe classes. 2. When using SynchronizedList, manual synchronization is required when traversing . 3.SynchronizedList can specify the locked object.

Guess you like

Origin blog.csdn.net/zy_dreamer/article/details/132350309