java证明ArrayList和HashMap的非线程安全性
通过可复现的 Java 示例,展示多线程并发修改 ArrayList 与 HashMap 时出现的错误。
众所周知, 这两个结构都不是线程安全的.对于ArrayList, 可以通过多个线程向其添加元素, 若它不是线程安全的, 则最后它实际存储的元素数量很可能不等于实际添加的元素数量.HashMap的验证方法也类似
需要注意的是, 这里的线程不安全指的是原子操作, 比如add这种, 得不到预期效果, 而不是add和get这样一组操作. 在原子操作线程安全的情况下, 一组原子操作也是线程不安全的, 需要另外加锁.
证明ArrayList的非线程安全性
package com.ibm.javacore.collections.threadsafe;
import java.util.ArrayList;import java.util.Collections;import java.util.List;import java.util.Random;
public class ThreadSafeDemo { public static int demo(final List list, final int testCount) throws InterruptedException { ThreadGroup group = new ThreadGroup(list.getClass().getName() + "@" + list.hashCode()); final Random rand = new Random();
Runnable listAppender = new Runnable() { public void run() { try { Thread.sleep(rand.nextInt(2)); } catch (InterruptedException e) { return; } list.add("0"); } };
for (int i = 0; i < testCount; i++) { new Thread(group, listAppender, "InsertList-" + i).start(); }
while (group.activeCount() > 0) { Thread.sleep(10); }
return list.size(); } public static void main(String[] args) throws InterruptedException { List unsafeList = new ArrayList(); List safeList = Collections.synchronizedList(new ArrayList()); final int N = 10000; for (int i = 0; i < 10; i++) { unsafeList.clear(); safeList.clear(); int unsafeSize = demo(unsafeList, N); int safeSize = demo(safeList, N); System.out.println("unsafe/safe: " + unsafeSize + "/" + safeSize); } }}证明HashMap的非线程安全性
package com.concurrence;
import java.util.HashMap;
public class ThreadNotSafeHashmap { public static void main(String args[]) throws InterruptedException { final HashMap<String, String> firstHashMap = new HashMap<String, String>(); Thread t1 = new Thread() { public void run() { for (int i = 0; i < 2500; i++) { firstHashMap.put(String.valueOf(i), String.valueOf(i)); } } }; Thread t2 = new Thread() { public void run() { for (int j = 2500; j < 5000; j++) { firstHashMap.put(String.valueOf(j), String.valueOf(j)); } } }; t1.start(); t2.start();
Thread.sleep(1000); for (int k = 0; k < 5000; k++) { if (!String.valueOf(k).equals(firstHashMap.get(String.valueOf(k)))) { System.err.println(String.valueOf(k) + ":" + firstHashMap.get(String.valueOf(k))); } } }}