并发下的ArrayList

  我们都知道,ArrayList是一个线程不安全的容器。如果在多线程中使用ArrayList,可能会导致程序出错。但是问题出现在哪里呢?看一下下边的代码:

public class ArrayListMultiThread {
	
	static Vector<Integer> al = new Vector<Integer>();

	public static class AddThread implements Runnable {

		@Override
		public void run() {
			// TODO Auto-generated method stub
			for (int i = 0; i < 1000000; i++) {
				al.add(i);
			}
		}

	}
	
	public static void main(String[] args) throws InterruptedException {
		Thread t1 = new Thread(new AddThread());
		Thread t2 = new Thread(new AddThread());
		t1.start();t2.start();
		t1.join();t2.join();
		System.out.println(al.size());
	}
}

  代码中t1和t2两个线程同时向一个ArrayList容器中添加数据。因此我们期待最后可以有2000000个元素在ArrayList中,如果你执行这段代码,你可能会得到三种结果。

  1. 程序正常结束,ArrayList的大小最终确实是2000000.这说明并行程序有问题,也未必会每次都表现出来。
  2. 抛出异常:这是因为ArrayList在扩容过程中,内部一致性被破坏,但由于没有锁的保护,另一个线程访问到了不一致的内容状态,导致出现越界问题。
Exception in thread "Thread-0" java.lang.ArrayIndexOutOfBoundsException: 10
	at java.util.ArrayList.add(ArrayList.java:459)
	at com.test.thread.ArrayListMultiThread$AddThread.run(ArrayListMultiThread.java:16)
	at java.lang.Thread.run(Thread.java:748)
1000009

  3.出现了一个非常隐蔽的错误,比如打印小于2000000的值显然,这是由于多线程访问冲突,使的保存容器大小的变量被多线程不正常的访问,同时两个线程同时对ArrayList中的同一个位置星星赋值导致的。

  改进的方法很简单,使用线程安全的Vector代替ArrayList即可。

posted on 2017-08-07 21:40  小晓俊  阅读(274)  评论(0编辑  收藏  举报