介紹
JDK中提供了很多集合實(shí)現(xiàn),本文不會介紹有哪些集合的接口以及實(shí)現(xiàn)類,而是介紹如何在多線程情況下使用這些集合。

如果您還不太了解Java的整個集合體系的話,請查看《Java開發(fā)成長之路第一年》。如果您還想要了解線程的相關(guān)內(nèi)容,請查看《Java多線程》。
線程不安全
java.util.HashMap、java.util.ArrayList、java.util.LinkedList、java.util.HashSet等集合實(shí)現(xiàn)類都是線程不安全的,在多線程環(huán)境下使用的話,將會得到無法預(yù)期的結(jié)果。
遍歷不安全
java.util.Hashtable、java.util.Vector等集合類在多線程環(huán)境下,如果只是調(diào)用put、get、remove等方法的話是能保證線程安全的,但如果進(jìn)行遍歷的話就無法保證線程安全了。這種情況也叫做“條件線程安全”。
線程安全
java.util.concurrent.ConcurrentHashMap、java.util.concurrent.CopyOnWriteArrayList、java.util.concurrent.ConcurrentArraySet等是線程安全的。
Map
下面是驗(yàn)證HashMap問題的示例代碼:
[codesyntax lang="java"]
import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;/** * java.util.HashMap的線程不安全測試,這里會有如下兩種情況: * <ul> * <li>輸出的Map元素個數(shù)不對</li> * <li>死循環(huán)(線程數(shù)多了更容易出現(xiàn))</li> * </ul> * @author suren * @date 2017年2月22日 下午3:31:09 /public class HashMapTest{ static Map<String, String> map; public static void main(String[] args) { map = new HashMap<String, String>(); long begin = System.currentTimeMillis(); ThreadGroup group = new ThreadGroup("HashMap thread test from surenpi.com"); List<Thread> threadList = new ArrayList<Thread>(); int threadCount = 10; for(int i = 0; i < threadCount; i++) { Thread thread = new Thread(group, new Runnable() { @Override public void run() { for(int j = 0; j < 200 ; j++) { map.put(Thread.currentThread().getName() + j, ""); map.get(Thread.currentThread().getName() + j); } } }); threadList.add(thread); } for(Thread thread : threadList) { thread.start(); } while(group.activeCount() > 0) {} System.out.println(map.size()); System.out.println("take time : " + (System.currentTimeMillis() - begin)); }}
[/codesyntax]
以下是線程安全的Map實(shí)現(xiàn)類的效率比較示例:
[codesyntax lang="java"]
import java.util.ArrayList;import java.util.Hashtable;import java.util.List;import java.util.Map;import java.util.concurrent.ConcurrentHashMap;/* * Hashtable和ConcurrentHashMap效率比較 * @author suren * @date 2017年2月22日 下午4:27:56 /public class ThreadSafeMapTest{ /* * @param args */ public static void main(String[] args) { mapTest(new Hashtable<String, String>()); mapTest(new ConcurrentHashMap<String, String>()); } static void mapTest(final Map<String, String> map) { long begin = System.currentTimeMillis(); ThreadGroup group = new ThreadGroup("HashMap thread test from surenpi.com"); List<Thread> threadList = new ArrayList<Thread>(); int threadCount = 10; for(int i = 0; i < threadCount; i++) { Thread thread = new Thread(group, new Runnable() { @Override public void run() { for(int j = 0; j < 9999 ; j++) { map.put(Thread.currentThread().getName() + j, ""); map.get(Thread.currentThread().getName() + j); } } }); threadList.add(thread); } for(Thread thread : threadList) { thread.start(); } while(group.activeCount() > 0) {} System.out.println(map.getClass() + " take time : " + (System.currentTimeMillis() - begin)); }}
[/codesyntax]
List
下面是ArrayList和LinkedList線程不安全的示例代碼:
[codesyntax lang="java"]
import java.util.ArrayList;import java.util.LinkedList;import java.util.List;/** * java.util.LinkedList和java.util.ArrayList的線程不安全測試,這里會有如下兩種情況: * <ul> * <li>ArrayList可能會出現(xiàn)下標(biāo)越界的異常</li> * <li>LinkedList的元素個數(shù)不正確</li> * </ul> * @author suren * @date 2017年2月22日 下午3:31:09 */public class NonThreadSafeListTest{ public static void main(String[] args) { listTest(new LinkedList<String>()); listTest(new ArrayList<String>()); } static void listTest(final List<String> list) { long begin = System.currentTimeMillis(); ThreadGroup group = new ThreadGroup("HashMap thread test from surenpi.com"); List<Thread> threadList = new ArrayList<Thread>(); int threadCount = 10; for(int i = 0; i < threadCount; i++) { Thread thread = new Thread(group, new Runnable() { @Override public void run() { for(int j = 0; j < 200 ; j++) { list.add(Thread.currentThread().getName() + j); } } }); threadList.add(thread); } for(Thread thread : threadList) { thread.start(); } while(group.activeCount() > 0) {} System.out.println(list.size()); System.out.println(list.getClass() + " take time : " + (System.currentTimeMillis() - begin)); }}
[/codesyntax]