11package base ;
22
3- import java .util .ArrayList ;
4- import java .util .Collections ;
5- import java .util .List ;
3+ import java .util .*;
64import java .util .concurrent .ConcurrentHashMap ;
75
8- import com .alibaba .fastjson .JSON ;
9- import com .google .gson .Gson ;
10-
11- import domain .target .TargetEntry ;
12-
136/**
14- *需要构造一个map,满足如下要求:
15- * 1、线程安全ConcurrentHashMap是线程安全的,但是不是按序存储。
16- * 2、尽可能快的查询速度。参考http://infotechgems.blogspot.com/2011/11/java-collections-performance-time.html
17- *
18- * 为了提高LineEntry的查找速度,改为使用LinkedHashMap,
19- * LinkedHashMap是继承于HashMap,是基于HashMap和双向链表来实现的。
20- * HashMap无序;LinkedHashMap有序,可分为插入顺序和访问顺序两种。默认是插入顺序。
21- * 如果是访问顺序,那put和get操作已存在的Entry时,都会把Entry移动到双向链表的表尾(其实是先删除再插入)。
22- * LinkedHashMap是线程不安全的。
23- *
24- * 虽然费劲找到了ConcurrentLinkedHashMap
25- * https://cayenne.apache.org/docs/3.1/api/org/apache/cayenne/util/concurrentlinkedhashmap/ConcurrentLinkedHashMap.html
26- * 但是他还是不能直接使用,依然要自己实现通过Index获取元素的方法,而且它还不能被继承。
27- *
28- * 所以再次修改,继承ConcurrentHashMap来自行实现。
29- * 参考:https://stackoverflow.com/questions/10387290/how-to-get-position-of-key-value-in-linkedhashmap-using-its-key
7+ * Thread-safe indexed map: keeps insertion order and supports get by index.
8+ * Uses a single monitor to synchronize updates that touch both the map and the index list.
309 */
31-
32- public class IndexedHashMap <K ,V > extends ConcurrentHashMap <K ,V > {
33-
34-
10+ public class IndexedHashMap <K , V > extends ConcurrentHashMap <K , V > {
3511 private static final long serialVersionUID = 1L ;
3612
37- /**
38- * 为了可以获取LinkedHashMap中元素的index。
39- */
40- private List < K > Index = Collections . synchronizedList ( new ArrayList < K >() );
13+ // index list - protected by `indexLock` for operations that must be atomic with the map
14+ private final List < K > index = new ArrayList <>();
15+ // single lock to protect cross-structure invariants
16+ private final Object indexLock = new Object ( );
4117
42- /**
43- * LinkedHashMap的方法
44- * @param key
45- * @param val
46- * @return 如果已经存在相同的key,这返回之前的值,否则返回空。the previous value associated with key, or null if there was no mapping for key
47- */
4818 @ Override
49- public V put (K key ,V val ) {
50- V returnValue = super .put (key ,val );
51- if (returnValue == null ) {
52- Index .add (key );//相比super.containsKey(key)的判断,这样写可以减少一次查找,提高速度
19+ public V put (K key , V val ) {
20+ // We need to ensure the map update and index update are atomic w.r.t each other.
21+ synchronized (indexLock ) {
22+ V previous = super .put (key , val );
23+ if (previous == null ) {
24+ // new mapping: append to index list
25+ index .add (key );
26+ } else {
27+ // existing mapping replaced: keep index list unchanged
28+ }
29+ return previous ;
5330 }
54- return returnValue ;
5531 }
56-
32+
5733 @ Override
5834 public V remove (Object key ) {
59- V returnValue = super .remove (key );
60- if (returnValue != null ) {
61- Index .remove (key );
35+ synchronized (indexLock ) {
36+ V previous = super .remove (key );
37+ if (previous != null ) {
38+ // remove first occurrence from index list
39+ index .remove (key );
40+ }
41+ return previous ;
6242 }
63- return returnValue ;
6443 }
6544
6645 /**
67- * 为了符合平常的使用习惯,减少出错.
68- * 根据index删除
69- *
70- * @param index
71- * @return
46+ * Remove by index (returns the removed value)
7247 */
73- public V remove (int index ) {
74- K key = (K ) Index .get (index );
48+ public V remove (int idx ) {
49+ K key ;
50+ synchronized (indexLock ) {
51+ key = index .get (idx );
52+ // reuse remove(Object) which already synchronizes
53+ }
7554 return remove (key );
7655 }
7756
7857 /**
79- * 为了符合平常的使用习惯,减少出错
80- * @param index
81- * @return
58+ * Get by index
8259 */
83- public V get (int index ){
84- K key = (K ) Index .get (index );
85- return get (key );
60+ public V get (int idx ) {
61+ K key ;
62+ synchronized (indexLock ) {
63+ key = index .get (idx );
64+ }
65+ return super .get (key );
8666 }
8767
8868 @ Override
@@ -91,61 +71,33 @@ public V get(Object key) {
9171 }
9272
9373 /**
94- * synchronizedList的indexOf方法是线程安全的
95- * public int indexOf(Object o) {
96- synchronized (mutex) {return list.indexOf(o);}
97- }
98-
99- * @param key
100- * @return
74+ * Return index of key. This method is synchronized on indexLock to keep view consistent.
10175 */
102- public int IndexOfKey (K key ) {
103- return Index .indexOf (key );
76+ public int indexOfKey (K key ) {
77+ synchronized (indexLock ) {
78+ return index .indexOf (key );
79+ }
10480 }
105-
81+
10682 @ Override
10783 public int size () {
108- if (Index .size () != super .size ()) {
109- throw new IllegalArgumentException ("IndexedHashMap error: size not match!!! " + Index .size () +" " + super .size ());
110- }
111- return super .size ();
112- }
113-
114- public static void test () {
115- IndexedHashMap <String ,TargetEntry > targetEntries =new IndexedHashMap <String ,TargetEntry >();
116- targetEntries .put ("1111" ,new TargetEntry ("www.baidu.com" ));
117-
118- String str = JSON .toJSONString (targetEntries );
119- System .out .println (str );
120- System .out .println ( JSON .parseObject (str ,IndexedHashMap .class ));
121- //https://blog.csdn.net/qq_27093465/article/details/73277291
122-
123- String str1 = JSON .toJSONString (targetEntries );
124- System .out .println (str1 );
125- System .out .println ( new Gson ().fromJson (str ,IndexedHashMap .class ));
84+ synchronized (indexLock ) {
85+ int idxSize = index .size ();
86+ int mapSize = super .size ();
87+ if (idxSize != mapSize ) {
88+ // keep the error behavior for early detection, but provide helpful message
89+ throw new IllegalStateException ("IndexedHashMap error: size not match!!! index.size="
90+ + idxSize + " map.size=" + mapSize );
91+ }
92+ return mapSize ;
93+ }
12694 }
127- public static void test1 () {
128- IndexedHashMap aaa = new IndexedHashMap ();
129- aaa .put ("1" , "a" );
130- aaa .put ("2" , "b" );
131- aaa .put ("3" , "c" );
132- aaa .put ("4" , "d" );
133- aaa .put ("5" , "e" );
134- aaa .put ("6" , "f" );
135- aaa .put ("7" , "g" );
136- aaa .put ("7" , "x" );
137-
13895
139- //System.out.println("index of 4: "+aaa.IndexOfKey("4"));
140- //aaa.remove("2");
141- //aaa.put("7", "x");
142- System .out .println (aaa .get ("1" ));
143- System .out .println (aaa .get (1 ));
144- //System.out.println("index of 4: "+aaa.IndexOfKey("4"));
145- }
146- public static void main (String [] args ) {
147- test ();
148- test1 ();
96+ // optional helpers
97+ public K keyAt (int idx ) {
98+ synchronized (indexLock ) {
99+ return index .get (idx );
100+ }
149101 }
150-
151102}
103+
0 commit comments