Set (vi) LINKEDHASHMAP

Source: Internet
Author: User
Tags list of attributes repetition

The last two articles on HashMap and HashMap in the multi-threaded problem, explained that, HashMap is a very common, very useful collection, and in the multi-threaded case of improper use of thread security issues.

In most cases, the map can use HashMap as long as it does not involve thread safety, but there is a problem with HashMap that the order of iteration HashMap is not the order of HashMap placement , which is unordered. This drawback of hashmap is often troubling, because there are scenarios where we expect an orderly map.

At this time, linkedhashmap the debut, although it increased the cost of time and space, but by maintaining a two-way list running on all items, Linkedhashmap guarantees the sequence of elements iteration .

Four points of concern on the Linkedhashmap answer

Focus Point Conclusion
Linkedhashmap whether NULL is allowed Both key and value allow null
Linkedhashmap whether duplicate data is allowed Key repetition overrides, value allows repetition
Whether the Linkedhashmap is orderly Ordered
Linkedhashmap is thread safe Non-thread safe

LINKEDHASHMAP Basic Structure

About Linkedhashmap, first mention two points:

1. Linkedhashmap can be considered as hashmap+linkedlist, that is, it uses HASHMAP to manipulate the data structure, and uses LinkedList to maintain the order of the inserted elements.

2, Linkedhashmap the basic realization of the idea is----polymorphism. It can be said that understanding polymorphism, and then to understand the LINKEDHASHMAP principle will be more effective, conversely, for the linkedhashmap principle of learning can also promote and deepen the understanding of polymorphism.

Why do you say so, first look at the definition of Linkedhashmap:

public class linkedhashmap<k,v>    extends hashmap<k,v>    implements map<k,v>{    ...}

See, Linkedhashmap is HashMap subclass, natural Linkedhashmap also inherit hashmap all non-private methods. Take a look at the methods in Linkedhashmap itself:

See Linkedhashmap There is no way to manipulate the data structure, that is to say linkedhashmap manipulate data structures (such as put a data), and HashMap operation of the method of the same way, nothing but the details of some of the difference.

The difference between Linkedhashmap and HashMap lies in their basic data structure, looking at the basic data structure of LINKEDHASHMAP, which is entry:

private static class Entry<k,v> extends Hashmap.entry<k,v> {    //These fields comprise the doubly linked Li St used for iteration.    Entry<k,v> before, after; Entry (int hash, K key, V value, hashmap.entry<k,v> next) {        super (hash, key, value, next);    }    ...}

Let's list some of the properties in entry:

1, K key

2, V value

3, entry<k, v> next

4, int hash

5, Entry<k, v> before

6, entry<k, v> after

The first four, that is, the red part is inherited from the Hashmap.entry, the following two, that is, the blue part is Linkedhashmap unique. Don't make a mistake. Next and before, after,next are the order of the entry that are used to maintain hashmap at the specified table location, before, after is the order in which entry insertions are maintained .

or figure it out, make a list of attributes:

Initialize Linkedhashmap

If there is a code like this:

1 public static void main (string[] args) 2 {3     linkedhashmap<string, string> linkedhashmap =4             New Linkedhashmap<string, String> (), 5     linkedhashmap.put ("111", "111"), 6     linkedhashmap.put ("222", "222") ; 7}

First is line 3rd ~ 4th line, new one linkedhashmap out and see what has been done:

1 public Linkedhashmap () {2 super (); 3     Accessorder = false; 4}
1 public HashMap () {2     this.loadfactor = default_load_factor;3     threshold = (int) (Default_initial_capacity * Default_load_factor); 4     table = new entry[default_initial_capacity];5     init (); 6}
1 void init () {2     header = new entry<k,v> ( -1, NULL, NULL, NULL); 3     header.before = Header.after = header; 4}
/** * The head of the doubly linked list. */private transient entry<k,v> header;

Here comes the first polymorphic: Init () method. Although the init () method is defined in HashMap, it is because:

1, Linkedhashmap rewrite the Init method

2, the instantiation is Linkedhashmap

So the actual invocation of the Init method is the Linkedhashmap rewrite of the Init method. Assuming that the address of the header is 0x00000000, then the initialization is complete, which is actually the case:

Linkedhashmap adding elements

Continue to see Linkedhashmap add element, that is put ("111", "111") do what, first of all, of course, call the HashMap put method:

1 public V put (K key, V value) {2     if (key = = null) 3         return Putfornullkey (value); 4     int hash = hash (KEY.HASHC Ode ()); 5     int i = indexfor (hash, table.length), 6 for     (entry<k,v> e = table[i]; E! = null; e = e.next) {7         objec T k; 8         if (E.hash = = Hash && (k = e.key) = = Key | | key.equals (k))) {9             V oldValue = e.value;10             e.value = V Alue;11             e.recordaccess (this);             return oldvalue;13         }14     }15     AddEntry (hash, key, value, I);     return null;19}

Line 17th is also polymorphic, because Linkedhashmap overrides the AddEntry method, so AddEntry calls the method that Linkedhashmap overrides:

1 void addentry (int hash, K key, V value, int bucketindex) {2     createentry (hash, key, value, Bucketindex); 3  4
   
    //Remove eldest entry if instructed, else grow capacity if appropriate 5     entry<k,v> eldest = Header.after; 6
    if (Removeeldestentry (eldest)) {7         removeentryforkey (Eldest.key); 8     } else {9         if (size >= threshold) Ten             Resize (2 * table.length);     }12}
   

Because Linkedhashmap itself maintains the order of insertions, so linkedhashmap can be used to do the cache, line 5th ~ 7th row is used to support the FIFO algorithm, here temporarily do not care about it. Take a look at the Createentry method:

1 void createentry (int hash, K key, V value, int bucketindex) {2     hashmap.entry<k,v> old = table[bucketindex];3< c13/>entry<k,v> e = new entry<k,v> (hash, key, value, old); 4     Table[bucketindex] = e;5     E.addbefore ( header); 6     Size++;7}
private void Addbefore (entry<k,v> existingentry) {    after  = existingentry;    before = Existingentry.before;    Before.after = this;    After.before = this;}

Lines 2nd ~ 4th line of code and HashMap no different, the newly added elements placed on table[i], the difference is linkedhashmap also do addbefore operation, the four lines of code means that the new entry and the original linked list to generate a doubly linked list. Assuming that the string 111 is placed on position table[1], the generated entry address is 0x00000001, then this is shown in the figure:

If you are familiar with LinkedList source code should not be difficult to understand, or to explain, note that Existingentry represents the header:

1, After=existingentry, that is, the addition of the entry After=header address, that is after=0x00000000

2, Before=existingentry.before, that is, the new entry before is the header of the before address, the header of the before at this time is 0x00000000, so added entry before= 0x00000000

3, Before.after=this, the new entry before at this time for 0x00000000 that is Header,header after=this, that is, the header of the after=0x00000001

4, After.before=this, the new entry after this time for 0x00000000 that is Header,header before=this, that is, the header of the before=0x00000001

In this way, a doubly linked list of headers and new entry is formed. Look again, what is new after the string 222, assuming that the address of the new entry is 0x00000002, generated to table[2], shown in the figure is this:

It is not fine to explain, as long as before, after cleared to know the representative of which entry will not have any problems.

Always see, again, the implementation of LINKEDHASHMAP is the implementation of hashmap+linkedlist, in order to hashmap maintain data structure, in a linklist way to maintain the order of insertion.

Implementation of LRU algorithm cache using Linkedhashmap

In front of the Linkedhashmap add elements, delete, modify the elements do not say, relatively simple, and hashmap+linkedlist Delete, modify the same elements, the following is a new content.

Linkedhashmap can be used as a cache, for example LRUCache, to look at the code of this class, very simple, just more than 10 lines:

public class LRUCache extends linkedhashmap{public    LRUCache (int maxSize)    {        super (MaxSize, 0.75F, true);        maxelements = maxSize;    }    Protected Boolean removeeldestentry (Java.util.Map.Entry eldest)    {        return size () > maxelements;    }    Private static final long serialversionuid = 1L;    protected int maxelements;}

As the name implies, LRUCache is based on the LRU algorithm cache (caching), this class inherits from Linkedhashmap, and the class sees no special method, this shows that LRUCache implementation of the cache LRU functionality is derived from Linkedhashmap. Linkedhashmap can implement the LRU algorithm's cache based on two points:

1, LinkedList First it is a map,map is based on k-v, and the cache is consistent

2. LinkedList provides a Boolean value that allows the user to specify whether to implement the LRU

So, first we understand what is LRU:LRU is least recently used, which is least recently used, that is, when the cache is full, the most recently infrequently accessed data is first eliminated. For example, data A, accessed 1 days ago, the data b,2 days ago, the cache is full, priority will be the elimination of data B.

Let's take a look at the construction of LinkedList with a Boolean parameter:

Public Linkedhashmap (int initialcapacity,         float Loadfactor,                     boolean accessorder) {    super ( Initialcapacity, loadfactor);    This.accessorder = Accessorder;}

This is the accessorder, which says:

(1) False, all entry in the order in which they are inserted

(2) True, all entry are arranged in the order in which they are accessed

The 2nd meaning is that if there are 1 2 3 of these 3 entry, then visit 1, then move 1 to the tail, that is 2 3 1. Every time the access to the data is moved to the end of the two-way queue, then each time to retire the data, the two-way queue the most data is not the most infrequently accessed the data? In other words, the data at the top of the doubly linked list is the data to be retired.

"Access", the word has two meanings:

1, according to key to get value, that is, get method

2, modify the value of the key corresponding to the Put method

First look at the Get method, which is rewritten in Linkedhashmap:

Public V get (Object key) {    entry<k,v> e = (entry<k,v>) getentry (key);    if (E = = null)        return null;    E.recordaccess (this);    return e.value;}

Then the Put method, which inherits the HashMap of the parent class:

1 public V put (K key, V value) {2     if (key = = null) 3         return Putfornullkey (value); 4     int hash = hash (KEY.HASHC Ode ()); 5     int i = indexfor (hash, table.length), 6 for     (entry<k,v> e = table[i]; E! = null; e = e.next) {7         objec T k; 8         if (E.hash = = Hash && (k = e.key) = = Key | | key.equals (k))) {9             V oldValue = e.value;10             e.value = V Alue;11             e.recordaccess (this);             return oldvalue;13         }14     }15     AddEntry (hash, key, value, I);     return null;19}

The code that modifies the data is the line 6th ~ 14th. See both ends of the code have one thing in common: all call the Recordaccess method , and this method is the method in entry, that is, each time the recordaccess operation is a fixed entry.

Recordaccess, as the name implies, record access, that is, you visit the two-way linked list, I will write you down, how to record? Move the entry you visit to the tail . This method is an empty method in HashMap, which is used to record access for subclasses, and to see the implementation in Linkedhashmap:

void Recordaccess (hashmap<k,v> m) {    linkedhashmap<k,v> lm = (linkedhashmap<k,v>) m;    if (lm.accessorder) {        lm.modcount++;        Remove ();        Addbefore (Lm.header);    }}
private void Remove () {    before.after = after;    After.before = before;}
private void Addbefore (entry<k,v> existingentry) {    after  = existingentry;    before = Existingentry.before;    Before.after = this;    After.before = this;}

There are two things to see every time recordaccess:

1. Connect the front and rear entry of the entry to be moved

2, move the entry to the tail

Of course, all this is based on the Accessorder=true case. Finally, use a picture to show the whole recordaccess process:

Code demo Linkedhashmap The effect of sorting by Access order

The final code shows how the LinkedList is sorted in order of access, verifying the LRU functionality of the last part of Linkedhashmap:

public static void Main (string[] args) {    linkedhashmap<string, string> linkedhashmap =            new Linkedhashmap <string, String> (0.75f, true);    Linkedhashmap.put ("111", "111");    Linkedhashmap.put ("222", "222");    Linkedhashmap.put ("333", "333");    Linkedhashmap.put ("444", "444");    Looplinkedhashmap (LINKEDHASHMAP);    Linkedhashmap.get ("111");    Looplinkedhashmap (LINKEDHASHMAP);    Linkedhashmap.put ("222", "2222");    Looplinkedhashmap (Linkedhashmap);}    public static void Looplinkedhashmap (Linkedhashmap<string, string> linkedhashmap) {    set<map.entry< String, string>> set = Inkedhashmap.entryset ();    iterator<map.entry<string, string>> Iterator = Set.iterator ();        while (Iterator.hasnext ())    {        System.out.print (Iterator.next () + "\ t");    }    System.out.println ();}

Note that the construction method here is to use the three parameter and the last to pass in true, so that the order is sorted by access. Look at the result of the code run:

111=111    222=222    333=333    444=444    222=222    333=333    444=444    111=111    333=333    444=444    111=111    222=2222   

The result of the code operation proves two points:

1, the LinkedList is orderly

2. Each time an element is accessed (get or put), the element being accessed is referred to the last face.

Set (vi) LINKEDHASHMAP

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.