JAVA集合類:
java.util包下的HashSet和HashMap類不是線程安全的,
java.util.concurrent包下的ConcurrentHashMap類是線程安全的。
寫2個測試類來驗證下:
package com.cdfive.learn.thread;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* 驗證HashSet不是線程安全
*
* @author cdfive
* @date 2019-02-11
*/
public class HashSetTest {
public static void main(String[] args) {
final Set<Integer> set = new HashSet<>();// 結果可能大於1000
// final Set<Integer> set = Collections.synchronizedSet(new HashSet<>());// 結果等於1000
// final Set<Integer> set = Collections.newSetFromMap(new ConcurrentHashMap<Integer, Boolean>());// 結果等於1000
// 往set寫入1-1000
Runnable runnable = new Runnable() {
@Override
public void run() {
for (int i = 1; i <= 1000; i++) {
set.add(i);
}
}
};
int threadNum = 10;// 線程數
List<Thread> threadList = new ArrayList<>();
for (int i = 0; i < threadNum; i++) {
Thread thread = new Thread(runnable);
threadList.add(thread);
thread.start();
}
// 主線程等待子線程執行完成
for (Thread thread : threadList) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(set.size());// 結果可能大於1000
}
}
package com.cdfive.learn.thread;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 驗證HashMap不是線程安全
*
* @author cdfive
* @date 2019-02-11
*/
public class HashMapTest {
public static void main(String[] args) {
final Map<Integer, Integer> map = new HashMap<>();// 結果可能大於1000
// final Map<Integer, Integer> map = Collections.synchronizedMap(new HashMap<>());// 結果等於1000
// final Map<Integer, Integer> map = new ConcurrentHashMap<>();// 結果等於1000
// 往map寫入1-1000, key和value相同
Runnable runnable = new Runnable() {
@Override
public void run() {
for (int i = 1; i <= 1000; i++) {
map.put(i, i);
}
}
};
int threadNum = 2;// 線程數
List<Thread> threadList = new ArrayList<>();
for (int i = 0; i < threadNum; i++) {
Thread thread = new Thread(runnable);
threadList.add(thread);
thread.start();
}
// 主線程等待子線程執行完成
for (Thread thread : threadList) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(map.size());// 結果可能大於1000
}
}
如果需要保證線程安全的場景:
1.將HashSet或HashMap轉換為線程安全,使用Collections.synchronizedSet或Collections.synchronizedMap方法;
2.使用Collections.newSetFromMap(new ConcurrentHashMap<Integer, Boolean>())或使用java.util.concurrent包下的ConcurrentHashMap;
3.仍然使用HashSet或HashMap,使用時手動進行加鎖或同步;// 注意加鎖粒度,盡可能保證性能
在項目中根據實際場景進行選擇和應用。