ArrayList是不安全的。多个线程对ArrayList操作,会出现问题。
实例1
下面这个demo,主要测试内容:三个线程,一个线程向集合中add数据,一个线程从集合中remove数据,一个线程判断如果集合中有数据,从其中获取数据。运行程序,会报错:越界异常。
以下是异常图片:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| import java.util.ArrayList; import java.util.Collections; import java.util.List; public class ArrayListThreadTest { // private static List<String> TEST_LIST = new CopyOnWriteArrayList<String>(); private static List<String> TEST_LIST = Collections.synchronizedList(new ArrayList<String>()); // private static List<String> TEST_LIST = new ArrayList<>(); public static void main(String[] args) { new Thread(new Runnable() { @Override public void run() { while (true) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } TEST_LIST.add("11"); System.out.println("Thread1 running"); } } }).start(); new Thread(new Runnable() { @Override public void run() { while (true) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } TEST_LIST.clear(); System.out.println("Thread2 running"); } } }).start(); new Thread(new Runnable() { @Override public void run() { while (true) { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } if (TEST_LIST.size() > 0) { int size = TEST_LIST.size(); System.out.println(size + "===="); System.out.println(size + "===" + TEST_LIST.get(size-1)); } // System.out.println("Thread3 running"); } } }).start(); } }
|
实例2
演示内容:多个线程向集合arraylist、线程安全的arraylist中添加数据,集合长度不同。
下面例子则来源于:http://www.oschina.net/code/snippet_70229_2425
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Random; // Java语言: ArrayList的线程安全与不安全对比演示 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); } } }
|
总结
ArrayList是线程不安全的,多线程中,我们可以使用Collections.synchronizedList(list);
方法使其转换成安全的。或者我们也可以调用自己写的get、set、remove方法方法,自己方法内部加锁,调用list的get、set、remove方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class TestList { public static List<String> list = new ArrayList<>(); public static void addMessage(String message){ synchronized (TestList.class) { list.add(message); } } public static void getMessage(String message){ synchronized (TestList.class) { if (list.size() > 0) { list.remove(0); } } } }
|