In Java and thread-safe collections

Guide us know by Java Java Collections Framework (Collection Framework) How concurrent services, how we should use the collection (Collection) in single and multi-thread.
Topic a bit high, we are not well understood. So, I would simply point as described. Through this guide, you will be on Java collection of better understanding, and I can guarantee that this will be very useful in your daily coding.

1. Why do most of the collection class is not thread-safe?

Did you notice? Why most basic set implementation class is not thread-safe? For example: ArrayList, LinkedList, HashMap, HashSet , TreeMap, TreeSet and so on. In fact, all collection classes (except for Vector and HashTable) in the java.util package is not thread-safe, only left two implementation classes (Vector and HashTable) are thread-safe Why?
The reason: thread safe consumption is very expensive!
You should know, Vector and HashTable Java in history, appeared very early, the first time they are thread-safe design. (If you look at the source code, you will find the way to achieve these classes are synchronized modified) and their performance is very poor very quickly in multiple threads. As you know, the synchronization is required locks, lock it takes time to monitor, it reduces the performance.
This is why the new collection class does not provide concurrency control, in order to ensure maximum performance in a single thread.
The following test procedure verifies the Vector and ArrayList performance, two similar collections (Vector is thread safe, non-thread safe ArrayList)

import java.util.*;
 
/**
 * This test program compares performance of Vector versus ArrayList
 * @author www.codejava.net
 *
 */
public class CollectionsThreadSafeTest {
 
    public void testVector() {
        long startTime = System.currentTimeMillis();
 
        Vector<Integer> vector = new Vector<>();
 
        for (int i = 0; i < 10_000_000; i++) {
            vector.addElement(i);
        }
 
        long endTime = System.currentTimeMillis();
 
        long totalTime = endTime - startTime;
 
        System.out.println("Test Vector: " + totalTime + " ms");
 
    }
 
    public void testArrayList() {
        long startTime = System.currentTimeMillis();
 
        List<Integer> list = new ArrayList<>();
 
        for (int i = 0; i < 10_000_000; i++) {
            list.add(i);
        }
 
        long endTime = System.currentTimeMillis();
 
        long totalTime = endTime - startTime;
 
        System.out.println("Test ArrayList: " + totalTime + " ms");
 
    }
 
    public static void main(String[] args) {
        CollectionsThreadSafeTest tester = new CollectionsThreadSafeTest();
 
        tester.testVector();
 
        tester.testArrayList();
 
    }
 
}

Through each set of elements to add 10 million to test the performance results are as follows:

Test Vector: 9266 ms
Test ArrayList: 4588 ms

As you can see, at a relatively large data operation, almost twice the speed of the ArrayList Vector. You can also copy the above code under their own feelings.

2. Fail-fast iterators (Fail-Fast Iterators)

In using a collection, you have to understand that concurrency strategy iterator: Fail-Fast Iterators
after facie snippets, through a collection of type String:


List<String> listNames = Arrays.asList("Tom", "Joe", "Bill", "Dave", "John");
 
Iterator<String> iterator = listNames.iterator();
 
while (iterator.hasNext()) {
    String nextName = iterator.next();
    System.out.println(nextName);
}

Here we use the Iterator to traverse the elements in the list, imagine under listNames be shared by two threads: one thread executes traversal, traversing the time is not yet complete, the second set of threads to modify the operation (add or remove elements), you this guess what happens next?
Thread through the collection immediately thrown "ConcurrentModificationException", so called: the fail-fast iterators (random, Kazakhstan, is not so important to understand just OK)
Why iterator will throw an exception so quickly?
Because when a thread through the collection of time, in another loop through the collection of data modification would be very dangerous: the collection may be modified, there are more elements, or reduce one element or another element are gone. So consider the results when selecting throw an exception. And it should be found as early as possible, that's why. (Anyway, the answer is not what I want ~)

The following code demonstrates Throws: ConcurrentModificationException


import java.util.*;
 
/**
 * This test program illustrates how a collection's iterator fails fast
 * and throw ConcurrentModificationException
 * @author www.codejava.net
 *
 */
public class IteratorFailFastTest {
 
    private List<Integer> list = new ArrayList<>();
 
    public IteratorFailFastTest() {
        for (int i = 0; i < 10_000; i++) {
            list.add(i);
        }
    }
 
    public void runUpdateThread() {
        Thread thread1 = new Thread(new Runnable() {
 
            public void run() {
                for (int i = 10_000; i < 20_000; i++) {
                    list.add(i);
                }
            }
        });
 
        thread1.start();
    }
 
 
    public void runIteratorThread() {
        Thread thread2 = new Thread(new Runnable() {
 
            public void run() {
                ListIterator<Integer> iterator = list.listIterator();
                while (iterator.hasNext()) {
                    Integer number = iterator.next();
                    System.out.println(number);
                }
            }
        });
 
        thread2.start();
    }
 
    public static void main(String[] args) {
        IteratorFailFastTest tester = new IteratorFailFastTest();
 
        tester.runIteratorThread();
        tester.runUpdateThread();
    }
}

As you can see, in thread1 when traversing the list, thread2 add elements to perform the operation, this time an exception is thrown.
It should be noted that the use of iterator traversal list, fail-fast behavior is to let me earlier locate the problem. We should not rely on this to catch the exception, because the fail-fast behavior is not guaranteed. This means that if an exception is thrown, the program should be terminated immediately behavior rather than continue.
Now you should know how ConcurrentModificationException works, but it is best to avoid it.

Simultaneous package

At this point we understand, in order to ensure that maximize performance in single-threaded environment, so the basis of a set of implementation classes are not thread-safe. So what if we use a collection in a multithreaded environment do?
Of course, we can not use the thread-safe collection in a multithreaded environment, this will lead to our desired result. We can manually add their own synchronized block to ensure safety, but the use of automatic thread-safe threads wiser than we manually.
You should already know, Java Collections Framework provides a factory method to create a set of thread-safe, the format of these methods are as follows:

Collections.synchronizedXXX(collection)

This factory method encapsulates the specified collection and returns a set of thread-safe. XXX can be a Collection, List, Map, Set, SortedMap and SortedSet implementation class. For example, the following code creates a thread-safe list:

List<String> safeList = Collections.synchronizedList(new ArrayList<>());

If we already have a set of thread-safe, we can be packaged as a set of thread-safe by:

Map<Integer, String> unsafeMap = new HashMap<>();
Map<Integer, String> safeMap = Collections.synchronizedMap(unsafeMap);

As you can see the lock, packaging factory method specified collection, combined with a thread-safe return. In fact the basic interfaces have been, only to realize the added synchronized to achieve. So called: simultaneous package. Behind the working set are achieved by a package of this type.

Tip:
when we use the iterator to traverse the thread-safe collection of objects, we still need to add synchronized fields to ensure thread safety, because Iterator itself is not thread-safe, look at the following code:


List<String> safeList = Collections.synchronizedList(new ArrayList<>());
 
// adds some elements to the list
 
Iterator<String> iterator = safeList.iterator();
 
while (iterator.hasNext()) {
    String next = iterator.next();
    System.out.println(next);
}

In fact, we should be operated as:


synchronized (safeList) {
    while (iterator.hasNext()) {
        String next = iterator.next();
        System.out.println(next);
    }
}

At the same time reminding, Iterators also supports fail-fast.
Despite wrapper classes can guarantee thread-safe, but they still have their own shortcomings, see specific section below.

Concurrent collections

About synchronization disadvantages set is set as the target per se lock. This means that, when you traverse the object of other methods of this object has already been locked, causing other threads must wait. Other current thread can not operate this collection is locked, only when the lock release thread of execution. This results in lower overhead and performance.
That's why after jdk1.5 + provides a set of concurrent reasons, such as higher aggregate performance. Concurrent collections classes and placed under java.util.concurrent package, according to three security mechanisms are placed in three groups.

  • The first one is: copy-on-write collection: This collection of data on the array static in; change any data, will re-create a new array to record the value. This set is designed for use in a read operation is much greater than the write operation at the scene. There are two implementation classes as follows: CopyOnWriteArrayList and CopyOnWriteArraySet.
    It should be noted that the replication set does not throw an exception ConcurrentModificationException write. Because these collections is not supported by the variable group, Iterator to traverse the array variable values are never out, do not worry about the other thread modifies the data.

  • The second is: the exchange ratio for the collection, also known as CAS (Compare-And-Swap) Collection: This set is a collection of thread-safe algorithm implemented by CAS. CAS algorithm can be understood:
    in order to perform the calculation and update variables in the local copy of the variable, then no calculation is performed by obtaining access. When you are ready to update the variables, he will be compared with the value prior to the start of him, as if, then the updated value.
    If not, then the other thread should have been modified data. In this case, CAS thread can re-execute the calculated value, the update or abandon. There are a set of algorithms using CAS:. ConcurrentLinkedQueue and ConcurrentSkipListMap
    should be noted that, CAS does not have a coherent set of iterators, which means that they have created since not all of the changes are coming from the new array. He also ConcurrentModificationException not throw an exception.

  • The third type is: This set of objects using a special lock (java.util.concurrent.lock.Lock): This is the mechanism with respect to the conventional more flexible, it can be understood as follows:
    This lock and the same lock classic It has the basic functions, but under special circumstances and then also get: If the current is not locked, the timeout, the thread is not interrupted.
    Different from the synchronization code, when the method of execution, Lock has a lock will be held until you call the unlock method. Some mechanism to achieve this collection is divided into several parts to provide concurrent performance. For example: LinkedBlockingQueue, and at the end, so you can add and delete at the same time when the queue after opening.
    Other collections using this mechanism have: ConcurrentHashMap and most never realized BlockingQueue implementation class
    collection of the same class have no coherent iterators, ConcurrentModificationException not throw an exception.

Let's summarize a few points we learned today:

  1. Most of the implementation class in the java.util package are not thread-safe in order to ensure superior performance, in addition to the Vector and Hashtable.
  2. You can create a thread-safe class by Collection, but their relatively poor performance.
  3. SYNC set both to ensure the security thread is also given to ensure the performance of different algorithms, they are java.util.concurrent package. 

Translation from:
https://www.codejava.net/java-core/collections/understanding-collections-and-thread-safety-in-java

Guess you like

Origin www.cnblogs.com/deky97/p/11024527.html
Recommended