Java Concurrency Programming summary 4--concurrenthashmap improvements in jdk1.8 (RPM)

Source: Internet
Author: User

A brief review of the design of Concurrenthashmap in jdk1.7

A simple look at the design of Concurrenthashmap class in jdk1.7, its basic structure:

Each segment is a hashentry<k,v>[] table, and each element in the table is essentially a hashentry one-way queue. For example Table[3], the first node, Table[3]->next node 1, followed by Node 2, and so on.

public class concurrenthashmap<k, v> extends Abstractmap<k, v>        implements Concurrentmap<k, V> Serializable {    //divides the entire hashmap into several small maps, each segment is a lock; compared to Hashtable, the purpose of this design is to reduce concurrency conflicts for put, remove, and/    or Nodes that do not belong to the same fragment can operate concurrently, greatly improving performance    final segment<k,v>[] segments;    Essentially the Segment class is a small hashmap, where the table array stores the data for each node, inherits the Reentrantlock, and can be used as an interlock to use the    static final class Segment<k,v > extends Reentrantlock implements Serializable {        transient volatile hashentry<k,v>[] table;        transient int count;    }    Base node, store key, value    static final class Hashentry<k,v> {        final int hash;        Final K key;        volatile V value;        Volatile hashentry<k,v> Next;}    }

Second, in the jdk1.8 mainly made 2 aspects of improvement

Improved one: Cancel the Segments field, directly using the transient volatile hashentry<k,v>[] table to save data, using table array elements as a lock, so that each row of data to be locked, Further reduce the probability of concurrency conflicts.

Improved two: The original table array + unidirectional linked list data structure, changed to table array + one-way list + red black tree structure. For a hash table, the core capability is to distribute the key hash evenly across the array. If the hash is uniformly hashed, each queue length in the table array is 0 or 1. But the reality is not always so ideal, Although the Concurrenthashmap class default load factor is 0.75, but in the case of excessive data volume or bad luck, there will be some queue length is too long, if the use of a one-way list, then query a node of the time complexity of O (n); For a list of more than 8 (the default), the structure of the red-black tree is used in jdk1.8, so the time complexity of the query can be reduced to O (LOGN) to improve performance.

To illustrate the above 2 changes, see how the put operation is implemented.

Final V Putval (K key, V value, Boolean onlyifabsent) {if (key = = NULL | | value = NULL) throw new NullPointerException    ();    int hash = spread (Key.hashcode ());    int bincount = 0; For (node<k,v>[] tab = table;;)        {node<k,v> F; int n, I, FH; If the table is empty, initialize; otherwise, the array index i is computed based on the hash value, and if Tab[i] is empty, the node can be created directly.        Note: Tab[i] is essentially the first node of a linked list or red-black tree. if (tab = = NULL | |        (n = tab.length) = = 0) tab = inittable ();                         else if ((f = tabat (tab, i = (n-1) & hash)) = = null) {if (Castabat (tab, I, NULL,                   New node<k,v> (hash, key, value, NULL))) break;        No lock when adding to empty bin}//If tab[i] is not empty and the hash value is moved, indicating that the linked list is in the transfer operation, returning the table after the expansion is complete.        else if (fh = f.hash) = = MOVED) tab = Helptransfer (tab, f);            else {V oldval = null; Lock operations on the first node instead of segment, further reducing thread conflict synchronized (f) {if (Tabat (tab, I) = = f) {if (FH >= 0) {bincount = 1;                            for (node<k,v> e = f;; ++bincount) {K ek;                            If you find node E with a value of key in the list, set e.val = value directly.                                 if (E.hash = = Hash && (ek = e.key) = = Key | | (ek! = null && key.equals (EK))))                                {oldval = E.val;                                if (!onlyifabsent) e.val = value;                            Break                            }//If a node with a value of key is not found, create a new node and join the list.                            node<k,v> pred = e;                                                          if ((e = e.next) = = null) {Pred.next = new node<k,v> (hash, key,                                value, NULL); BReak;                    }}}//If the first node is of type Treebin, the description is red-black tree structure, perform puttreeval operation.                        else if (f instanceof treebin) {node<k,v> p;                        Bincount = 2; if (p = ((treebin<k,v>) f). Puttreeval (hash, key, value))! = Nu                            ll) {oldval = P.val;                        if (!onlyifabsent) p.val = value; }}}} if (Bincount! = 0) {//If the number of nodes is >=8, then the link junction                Structure of red and black trees.                if (Bincount >= treeify_threshold) treeifybin (tab, i);                if (oldval! = null) return oldval;            Break    }}}//Count increased by 1, it is possible to trigger the transfer operation (expansion).    Addcount (1L, Bincount); return null;} 

In addition, there are some minor improvements in other areas, such as new fields transient volatile countercell[] countercells; It is convenient to calculate the number of all elements in the HashMap, and the performance is much better than the size () method in jdk1.7.

Three, Concurrenthashmap jdk1.7, jdk1.8 performance comparison

The test procedure is as follows:

public class Compareconcurrenthashmap {private static concurrenthashmap<string, integer> map = new Concurrenthas    Hmap<string, integer> (40000);            public static void Putperformance (int index, int. num) {for (int i = index; i < (num + index); i++)    Map.put (String.valueof (i), i);        }public static void GetPerformance2 () {Long start = System.currenttimemillis ();        for (int i = 0; i < 400000; i++) Map.get (string.valueof (i));        Long end = System.currenttimemillis ();    System.out.println ("Get:it costs" + (End-start) + "MS");        public static void Main (string[] args) throws Interruptedexception {Long start = System.currenttimemillis ();        Final Countdownlatch Cdlatch = new Countdownlatch (4);            for (int i = 0; i < 4; i++) {final int finali = i; New Thread (New Runnable () {public void run () {compareconcurrenthashmap.putperformance ( 100000 * Finali, 100000);                Cdlatch.countdown ();        }}). Start ();        } cdlatch.await ();        Long end = System.currenttimemillis ();        System.out.println ("Put:it costs" + (End-start) + "MS");    Compareconcurrenthashmap.getperformance2 (); }}

The program runs multiple times after averaging, the results are as follows:

Four, collections.synchronizedlist and copyonwritearraylist performance analysis

Copyonwritearraylist a new array is copied to hold the new field when the thread changes it, so the write operation is poor While the Collections.synchronizedlist read operation uses the synchronized, so the reading performance is poor. The following is a test program:

public class App {private static list<string> ArrayList = Collections.synchronizedlist (New ARRAYLIST&LT;STRING&G    t; ());    private static list<string> copyonwritearraylist = new copyonwritearraylist<string> ();    private static Countdownlatch CDL1 = new Countdownlatch (2);    private static Countdownlatch CDL2 = new Countdownlatch (2);    private static Countdownlatch Cdl3 = new Countdownlatch (2);    private static Countdownlatch Cdl4 = new Countdownlatch (2);  Static Class Thread1 extends Thread {@Override public void run () {for (int i = 0; i < 10000;            i++) Arraylist.add (string.valueof (i));        Cdl1.countdown (); }} static Class Thread2 extends Thread {@Override public void run () {for (int i = 0; I & Lt 10000;            i++) Copyonwritearraylist.add (string.valueof (i));        Cdl2.countdown ();  }} static Class Thread3 extends Thread1 {@Override      public void Run () {int size = Arraylist.size ();            for (int i = 0; i < size; i++) arraylist.get (i);        Cdl3.countdown (); }} static Class Thread4 extends Thread1 {@Override public void run () {int size = Copyonw            Ritearraylist.size ();            for (int i = 0; i < size; i++) copyonwritearraylist.get (i);        Cdl4.countdown (); }} public static void Main (string[] args) throws Interruptedexception {Long Start1 = System.currenttimemill        Is ();        New Thread1 (). Start ();        New Thread1 (). Start ();        Cdl1.await ();        System.out.println ("arrayList Add:" + (System.currenttimemillis ()-Start1));        Long Start2 = System.currenttimemillis ();        New Thread2 (). Start ();        New Thread2 (). Start ();        Cdl2.await ();        System.out.println ("copyonwritearraylist Add:" + (System.currenttimemillis ()-Start2)); Long Start3 = SYSTEM.CUrrenttimemillis ();        New Thread3 (). Start ();        New Thread3 (). Start ();        Cdl3.await ();        System.out.println ("ArrayList Get:" + (System.currenttimemillis ()-start3));        Long start4 = System.currenttimemillis ();        New Thread4 (). Start ();        New Thread4 (). Start ();        Cdl4.await ();    System.out.println ("Copyonwritearraylist Get:" + (System.currenttimemillis ()-start4)); }}

The results are as follows:

Http://www.cnblogs.com/everSeeker/p/5601861.html

Java Concurrency Programming summary 4--concurrenthashmap improvements in jdk1.8 (RPM)

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.