ConcurrentHashMap 在 iterator 遍歷時候的是線程安全 的,Collections.synchronizedSortedMap 不是;
package test.lk; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import lombok.SneakyThrows; import org.apache.tomcat.util.modeler.ManagedBean; import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; /** * redis工具類 * * @version [版本號, 2016年7月27日] * @see [相關類/方法] * @since [產品/模塊版本] */ public final class TestColl { private SortedMap<String, Object> misMatchRptMap = Collections.synchronizedSortedMap(new TreeMap<>()); public static void main(String[] args) { test1(); } @SneakyThrows public static void main2(String[] args) { LoadingCache<String, String> cache = CacheBuilder.newBuilder() .maximumSize(5) .expireAfterWrite(10, TimeUnit.MINUTES) .build(new CacheLoader<String, String>() { @SneakyThrows @Override public String load(String id) { // 加載時,睡眠一秒 Thread.sleep(1000); return id + System.currentTimeMillis(); } }); // 異步線程加載 new Thread(() -> { try { System.out.println("執行get"); cache.get("key"); } catch (ExecutionException e) { e.printStackTrace(); } }).start(); // 異步線程移除 new Thread(() -> { // 睡眠,讓這個線程後執行 try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("執行invalidate"); cache.invalidate("key"); }).start(); // 按程序邏輯來說,我們應該拿到的結果是空map Thread.sleep(1200); System.out.println(cache.asMap()); } private static void test1() { // TreeMap Concurrent 線程安全.. SortedMap<String, ManagedBean> misMatchRptMap = Collections.synchronizedSortedMap(new TreeMap<>());
// Map<String, ManagedBean> misMatchRptMap = Collections.synchronizedMap(new HashMap<>()); 也是一樣的
// Map<String, ManagedBean> misMatchRptMap = new ConcurrentHashMap<>(); misMatchRptMap.put("aa", new ManagedBean()); // 類型是 Collections$SynchronizedSortedMap new Thread() { @Override public void run() { for (int i = 0; i < Integer.MAX_VALUE; i++) { misMatchRptMap.put("aa" + i, new ManagedBean()); try { Thread.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } } } }.start(); Timer timer = new Timer(); timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { // 雖然entries 是線程安全的,但是 // 這裏的iterator 不是Concurrent, 而是TreeMap 的 而是而是TreeMap的內部類: TreeMap.iterator Set<Map.Entry<String, ManagedBean>> entries = misMatchRptMap.entrySet(); // 雖然TreeMap 的entrySet 是線程安全的Collections$SynchronizedSet , 但是entrySet 的iterator 並不是 for (Iterator<Map.Entry<String, ManagedBean>> iterator = entries.iterator(); iterator.hasNext(); ) { Map.Entry<String, ManagedBean> next = iterator.next();// TreeMap$EntryIterator; 因爲 Collections$SynchronizedSet 沒有重寫iterator 方法,沒有提供線程安全的iterator , 這裏會報錯 System.out.println("next = " + next); iterator.remove(); } } }, 100, 5); } private static void test13() { List<String> list = new CopyOnWriteArrayList<>();// "Timer-0" java.lang.UnsupportedOperationException at java.util.concurrent.CopyOnWriteArrayList$COWIterator.remove(CopyOnWriteArrayList.java:1176) list.add("111"); list.add("222"); list.add("333"); new Thread() { @Override public void run() { for (int i = 0; i < Integer.MAX_VALUE; i++) { list.add(" ele " + i); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }.start(); Timer timer = new Timer(); timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { for(Iterator<String> iterator = list.iterator(); iterator.hasNext();){ String ele=iterator.next(); System.out.println("ele = " + ele); iterator.remove(); } System.out.println(list); } }, 100, 1000); } private static void test2() { List<String> list = new ArrayList<>(); list.add("111"); list.add("222"); list.add("333"); new Thread() { @Override public void run() { for (int i = 0; i < Integer.MAX_VALUE; i++) { list.add(" ele " + i); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } }.start(); Timer timer = new Timer(); timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { for(Iterator<String> iterator = list.iterator(); iterator.hasNext();){ String ele=iterator.next(); System.out.println("ele = " + ele); iterator.remove(); } System.out.println(list); } }, 100, 1000); } }
爲什麼呢?
一般的經驗是,我使用iterator.remove(); 就可以保證不會報錯了吧。
但是呢,iterator.remove(); 方法卻並不能保證線程安全! 沒有誰說 iterator.remove() 在多線程併發執行的情況下一定不報錯! 千萬不能記混哦!
其實,
雖然Collections.synchronizedSortedMap(new TreeMap<>()); 之後, TreeMap 的entrySet 是線程安全的Collections$SynchronizedSet , 但是entrySet 的iterator 並不是。
而 ConcurrentHashMap 裏面存在大量子類, 重寫了大部分的 集合相關的接口、類,確保了所有的集合操作、遍歷都是線程安全的!