Skip to content

Commit 79ee005

Browse files
committed
避免addNewLineEntryWithTime中的数组越界问题
1 parent ba3fc32 commit 79ee005

File tree

6 files changed

+261
-130
lines changed

6 files changed

+261
-130
lines changed

src/InternetSearch/SearchTableModel.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@ public void addNewEntry(SearchResultEntry entry){
324324
SearchResultEntry ret = lineEntries.put(key,entry);
325325
//以前的做法是,put之后再次统计size来判断是新增还是替换,这种方法在多线程时可能不准确,
326326
//concurrentHashMap的put方法会在替换时返回原来的值,可用于判断是替换还是新增
327-
int index = lineEntries.IndexOfKey(key);
327+
int index = lineEntries.indexOfKey(key);
328328
if (ret == null) {
329329
try {
330330
fireTableRowsInserted(index, index);

src/base/IndexedHashMap.java

Lines changed: 63 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -1,88 +1,68 @@
11
package base;
22

3-
import java.util.ArrayList;
4-
import java.util.Collections;
5-
import java.util.List;
3+
import java.util.*;
64
import 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+

src/base/IndexedHashMapOld.java

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
package base;
2+
3+
import java.util.ArrayList;
4+
import java.util.Collections;
5+
import java.util.List;
6+
import java.util.concurrent.ConcurrentHashMap;
7+
8+
import com.alibaba.fastjson.JSON;
9+
import com.google.gson.Gson;
10+
11+
import domain.target.TargetEntry;
12+
13+
/**
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
30+
*/
31+
32+
public class IndexedHashMapOld<K,V> extends ConcurrentHashMap<K,V> {
33+
34+
35+
private static final long serialVersionUID = 1L;
36+
37+
/**
38+
* 为了可以获取LinkedHashMap中元素的index。
39+
*/
40+
private List<K> Index = Collections.synchronizedList(new ArrayList<K>());
41+
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+
*/
48+
@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)的判断,这样写可以减少一次查找,提高速度
53+
}
54+
return returnValue;
55+
}
56+
57+
@Override
58+
public V remove(Object key) {
59+
V returnValue = super.remove(key);
60+
if (returnValue != null) {
61+
Index.remove(key);
62+
}
63+
return returnValue;
64+
}
65+
66+
/**
67+
* 为了符合平常的使用习惯,减少出错.
68+
* 根据index删除
69+
*
70+
* @param index
71+
* @return
72+
*/
73+
public V remove(int index) {
74+
K key = (K) Index.get(index);
75+
return remove(key);
76+
}
77+
78+
/**
79+
* 为了符合平常的使用习惯,减少出错
80+
* @param index
81+
* @return
82+
*/
83+
public V get(int index){
84+
K key = (K) Index.get(index);
85+
return get(key);
86+
}
87+
88+
@Override
89+
public V get(Object key) {
90+
return super.get(key);
91+
}
92+
93+
/**
94+
* synchronizedList的indexOf方法是线程安全的
95+
* public int indexOf(Object o) {
96+
synchronized (mutex) {return list.indexOf(o);}
97+
}
98+
99+
* @param key
100+
* @return
101+
*/
102+
public int IndexOfKey(K key) {
103+
return Index.indexOf(key);
104+
}
105+
106+
@Override
107+
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));
126+
}
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+
138+
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();
149+
}
150+
151+
}

0 commit comments

Comments
 (0)