public Map<String, List<Integer>> register(String userName, String passWd, int start, int end) throws InterruptedException {
List<Future<Map<String, List<Integer>>>> futures = new ArrayList<>();
Map<String, List<Integer>> listMap = new ConcurrentHashMap<>();
CountDownLatch downLatch = new CountDownLatch(end-start+1);
for (int i = start; i <= end; i++) {
int finalI = i;
int finalI1 = i;
Future<Map<String, List<Integer>>> submit = pool.submit(() -> {
Connection.Response user = Jsoup.connect(LOGIN_FORM_URL)
.method(Connection.Method.POST)
.referrer(REFERER_URL)
.data("u_user", userName + finalI1)
.data("u_pass", passWd)
.execute();
String errorMessage = user.body().replace("{F}","");
//synchronized(this){
if (listMap.containsKey(errorMessage)) {
listMap.get(errorMessage).add(finalI);
} else {
ArrayList<Integer> list = new ArrayList<>();
list.add(finalI);
listMap.put(errorMessage, list);
}
//}
return listMap;
});
futures.add(submit);
downLatch.countDown();
}
downLatch.await();
for (Future<Map<String, List<Integer>>> future : futures) {
try {
future.get();
}catch (Exception e){
log.error(Throwables.getStackTraceAsString(e));
}
}
return listMap;
}
这段代码这个位置还存在2处线程安全问题,具体位置如下:
if (listMap.containsKey(errorMessage)) {
listMap.get(errorMessage).add(finalI);
} else {
ArrayList list = new ArrayList<>();
list.add(finalI);
listMap.put(errorMessage, list);
}
正确结果:[4, 3, 5, 1, 7, 6, 9, 8,2]
-
if判断,如果list不存在就new一个,若开始多个进程同时进入else逻辑导致后面的new的list覆盖前面new的list,导致list数据比正常偏小
导致异常结果:[3, 4, 1, 8] -
ArrayList本身存在线程安全问题
list源码如下:
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!! 1
elementData[size++] = e; //2
return true;
}
先判断扩容,再进行赋值,所有存在多个线程在1,2之间,arraylist默认长度为10,两个线程都判断刚好是10都进入了第二步,则会出现一个线程下角标越界的异常出现。
最简单的解决方法就是加
synchronized(this){
}