The non-fast failure mechanism of ArrayList and the (basic) analysis of Vector and ArrayList

/**
 * 1. How does copyOnWriteArrayList realize (non-fastfail) non-fastfail mechanism? ? ?
 * 2. The underlying source code of Vector mainly depends on properties, constructors, addition, deletion, and modification methods, understanding the difference and connection between ArrayList and Vector
 * (underlying data structure, efficiency, expansion mechanism, thread safety)
 *
 */

1. Overview of ArrayList:  

   1. ArrayList is implemented based on an array. It is a dynamic array whose capacity can automatically grow, similar to the dynamic application of memory in C language, and the dynamic growth of memory.

   2. ArrayList is not thread-safe and can only be used in a single-threaded environment. In a multi-threaded environment, you can use the Collections.synchronizedList(List l) function to return a thread-safe ArrayList class, or you can use the CopyOnWriteArrayList class under the concurrent package.

  3. ArrayList implements the Serializable interface, so it supports serialization and can be transmitted through serialization: In this mechanism, an object can be represented as a sequence of bytes, which includes the data of the object and the type of object The type of information and data stored in the object. After the serialized object is written to the file, it can be read from the file and deserialized, that is to say, the type information of the object, the data of the object, and the data type in the object can be used in memory Create a new object in. The entire process is independent of the Java Virtual Machine (JVM), that is, an object serialized on one platform can be deserialized on a completely different platform.

5. The RandomAccess interface is implemented to support fast random access. In fact, it is fast access through the subscript sequence number:
E elementData(int index) {         return (E) elementData[index];     }

6、实现了Cloneable接口,能被克隆:
public Object clone() {
        try {
            ArrayList<?> v = (ArrayList<?>) super.clone();
            v.elementData = Arrays.copyOf(elementData, size);
            v.modCount = 0;
            return v;
        } catch (CloneNotSupportedException e) {
            // this shouldn't happen, since we are Cloneable
            throw new InternalError(e);
        }
    }

   7. ArrayList is not thread-safe; before adding a large number of elements to each ArrayList, the application can also use the ensureCapacity operation to increase the capacity of the ArrayList instance, which can reduce the number of incremental reallocations. Note that this implementation is not synchronous. If multiple threads access an ArrayList instance at the same time and at least one of them modifies the list structurally, then it must maintain external synchronization. (Involving fast failure mechanism)

   8. Fast-fail mechanism The self-protection mechanism of ArrayList
        *********The fast-failure mechanism actually depends on modCout: the number of storage structure modifications (addition and deletion, expansion, shrinkage), and the
    definition of expectedModCount against modCount For AbstractList, (ArrayList inherits AbstractList) 
when using iterator or foreach traversal, if the collection add/remove method is called to modify the structure of the collection, ConcurrentModification exception will be thrown.
   

   8.1. Single thread, insert new parameters while iterator traverses. Will cause fast failure

public class FastFailDemo {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            list.add(i);
        }
 
        for (Integer integer : list) {
            list.add(integer);
            System.out.println(integer);
        }
 
    }
}


  8.2. Single-threaded, using randomaccess to traverse the List, no fast failure occurs even when reading and writing

public class FastFailDemo {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            list.add(i);
        }
        for(int i =0 ; i< list.size(); i++) {
            list.add(i);
            System.out.println(i);
        }
 
    }
}

  8.3. Multi-threaded. When one thread reads, another thread writes to the list, the reading thread will fail quickly
public class FastFailDemo {     public static void main(String[] args) {         List<Integer> list = new ArrayList<>() ;         for (int i = 0; i <10; i++) {             list.add(i);         }         new MyThread1(list).start();         new MyThread2(list).start();     } } class MyThread1 extends Thread {     private List<Integer> list;     public MyThread1( List<Integer> list) {         this.list = list;     }     @Override     public void run() {         for (Integer integer: list) {









 


 



 



            System.out.println("MyThread1" + list.size());
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
 
class MyThread2 extends Thread {
    private List<Integer> list;
 
    public MyThread2( List<Integer> list) {
        this.list = list;
    }
 
    @Override
    public void run() {
 
        for (int i = 0; i < 10; i++) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            list.add(i);
            System.out.println("MyThread2 " + list.size());
        }
    }
}


2. The non-fast failure mechanism of arrayLsit and the comparison with the underlying implementation of vector

1. Non-fast failure mechanism

1) The fail-fast mechanism is an error detection mechanism. It can only be used to detect errors, because the JDK does not guarantee that the fail-fast mechanism will happen. If the set of fail-fast mechanisms is used in a multi-threaded environment, use "classes under java.util.concurrent package" to replace "classes under java.util package".
Replace the code:
List<Integer> list = new ArrayList<>();
with:
List<Integer> list = new CopyOnWriteArrayList<>();

2),
CopyOnWriteArrayList is different from ArrayList:

(01) Unlike ArrayList inheriting from AbstractList, CopyOnWriteArrayList does not inherit from AbstractList, it just implements the List interface.
(02) The Iterator returned by the iterator() function of ArrayList is implemented in AbstractList; and CopyOnWriteArrayList implements Iterator by itself.
(03) When next() is called in the Iterator implementation class of ArrayList, "checkForComodification() is called to compare the sizes of'expectedModCount' and'modCount'"; however, there is no so-called checkForComodification() in the Iterator implementation class of CopyOnWriteArrayList ConcurrentModificationException will not be thrown!
Although the size of the updated ArrayList is obtained; however, the result of the current iteration is not the updated arrayList;
public class FastFailDemo {     public static void main(String[] args) {         List<Integer> list = new CopyOnWriteArrayList<>( );         for (int i = 0; i <5; i++) {             list.add(i);         }         new MyThread1(list).start();






        new MyThread2(list).start();
    }
}
 
class MyThread1 extends Thread {
    private List<Integer> list;
 
    public MyThread1( List<Integer> list) {
        this.list = list;
    }
 
    @Override
    public void run() {
        for (Integer integer : list) {
            System.out.println("MyThread1 大小:" + list.size() + " 当前值:" + integer);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
 
class MyThread2 extends Thread {
    private List<Integer> list;
 
    public MyThread2( List<Integer> list) {
        this.list = list;
    }
 
    @Override
    public void run() {
 
        for (int i = 5; i < 10; i++) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            list.add(i);
            System.out.println("MyThread2 大小:" + list.size());
        }
    }
}

2. ArrayList:
     1) Keyword explanation: transient. (
     Used in serialization ) Java's serialization provides a mechanism for persisting object instances. When persisting an object, there may be a special object data member, and we don't want to use the serialization mechanism to save it. In order to turn off serialization on a domain of a specific object, you can add the keyword transient before this domain.
    public class UserInfo implements Serializable {  
     private static final long serialVersionUID = 996890129747019948L;  
     private String name;  
     private transient String psw;  
   
     public UserInfo(String name, String psw) {  
         this.name = name;  
         this.psw = psw;  
     }  
   
     public String toString( ) {  
         return "name=" + name + ", psw=" + psw;  
     }  
 }  
   
 public class TestTransient {  
     public static void main(String[] args) {  
         UserInfo userInfo = new UserInfo("Zhang San", "123456");  
         System.out.println(userInfo);  
         try {  
             // Serialization, the attribute set to transient is not Serialized  
             ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream(  
                     "UserInfo.out"));  
             o.writeObject(userInfo);  
             o.close();  
         } catch (Exception e) {  
             // TODO: handle exception  
             e.printStackTrace( );  
         }  
         try {  
             // Re-read the content  
             ObjectInputStream in = new ObjectInputStream(new FileInputStream(  
                     "UserInfo.out"));  
             UserInfo readUserInfo = (UserInfo) in.readObject();  
             //The content of psw after reading is null  
             System.out.println(readUserInfo.toString());  
         } catch (Exception e) {  
             // TODO: handle exception  
             e.printStackTrace();  
         }  
     }  
 }
     2) Construction method: 
   ArrayList provides three types of constructors, which can construct an empty list with a default initial capacity of 10 and an empty list with a specified initial capacity List and construct a list containing the elements of the specified collection, which are arranged in the order in which the collection's iterator returns them.
    // ArrayList has a constructor with capacity.    
    public ArrayList(int initialCapacity) {    
        super();    
        if (initialCapacity <0)    
            throw new IllegalArgumentException("Illegal Capacity: "+    
                                               initialCapacity);    
        // Create a new array    
        this.elementData = new Object[initialCapacity];    
    }    
   
    // ArrayList has no parameter constructor. The default capacity is 10.    
    public ArrayList() {    
        this(10);    
    }    
   
    // Create an ArrayList containing collection    
    public ArrayList(Collection<? extends E> c) {    
        elementData = c.toArray();    
        size = elementData.length;    
        if (elementData.getClass () != Object[].class)    
            elementData = Arrays.copyOf(elementData, size, Object[].class);    
    }
    3), element storage:

ArrayList provides set(int index, E element), add(E e), add(int index, E element), addAll(Collection<? extends E> c), addAll(int index, Collection<? extends E> c ) These methods of adding elements.

    4), directly read the element
     5), delete the element E remove(int index); boolean remove(Object o); void fastRemove(int index); removeRange(int fromIndex,int toIndex)


   
2. For ArrayList, it implements the List interface and uses an array at the bottom to store all elements. The operation is basically the operation of the array. In fact, Vector is basically the operation of arrays;
1) Similarities:
   (1) The implementation of Vector and ArrayList can be seen very similar (the bottom layer is an array), the addition, deletion, modification, and checking methods are similar, and they are also fast Failure mechanism
   (2), method of expanding capacity ensureCapacityHelper.
         Like ArrayList, Vector must call this method to ensure sufficient capacity every time it adds elements (may be 1, or a group). When the capacity is not enough to accommodate the current number of elements, first check whether the capacity increase parameter CapacityIncrement passed in the construction method is 0, if it is not 0, set the new capacity to the capacity plus the capacity increase, if If it is 0, set the new capacity to twice the old capacity. If the new capacity after setting is not enough, directly set the new capacity as the passed parameter (that is, the required capacity), and then use Arrays.copyof as well. The () method copies the elements to the new array.
    (3) Similarly, in the method of finding the index value of a given element, both of them divide the value of the element into null and non-null. The vector also allows the element to be null.

2) The difference between ArrayList and Vector is as follows:
(1) When the memory is insufficient, ArrayList is expanded by 0.5 times by default, and Vector is expanded by 1 times by default.
(2) Vector provides indexOf(obj, start) interface, ArrayList does not.
(3) Vector belongs to the thread safety level, but Vector is not used in most cases, because thread safety requires greater system overhead (many methods add synchronized synchronization statements to ensure thread safety).

Guess you like

Origin blog.csdn.net/sxy3180911/article/details/108691833