ArrayList和Vector线程安全问题(新手提问)

我有一段关于ArrayLisy和Vector线程安全的代码,如下:


import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

public class SynchronizedCollectionsTest {

static List<Integer> list = new ArrayList<Integer>(20);
static List<Integer> vector = new Vector<Integer>();

public static void main(String[] args) {
Thread thread1 = new Thread() {
public void run() {
for (int i = 0; i < 10; i++) {
list.add(list.size(), i);
vector.add(vector.size(), i);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
System.out.println(e);
}
}
}
};

Thread thread2 = new Thread() {
public void run() {
for (int i = 0; i < 10; i++) {
list.add(list.size(), i);
vector.add(vector.size(), i);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
System.out.println(e);
}
}
}
};

thread1.start();
thread2.start();

try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
System.out.println(e);
}
System.out.println(list);
System.out.println(vector);
}

}


现在想请教各位,list集合是如何产生出null的?

你看这段代码:
List list = new ArrayList();
list.add(0, 1);
list.add(0, 1);
list.add(2, 2);
System.out.println(list);
打印出来的结果是[1, 1, 2]
在同一位置赋值两次,下个位置不是null是1,从源代码看就是将1往后挪动了一个位置。
还有,如果中间某一个位置没有赋值的话,就抛出 java.lang.IndexOutOfBoundsException。
我是不是钻牛角尖了啊,呵呵

你理解错了
你这样直接add是没有错
因为add方法里面已经帮你做了往后移动数组的操作了
源代码里面的操作,移动数组和赋值操作分开的
所以先移动两次,再赋值的话,两次都是赋给了同一位置,后面那个位置没有被赋值
所以是空
你要看源代码 看外面的话,由于封装了很多,没法理解的

其实这个不需要太深的去研究
你只要记得ArrayList是非线程安全的,在add的时候需要加锁就ok了

我运行了下
正常的哈……
怎么会打印出null?


你给list的add操作加个同步锁
List类的add方法是非同步的 线程不安全
意思就是两个线程不能同时add

Vector是线程安全的
不需要加锁

刚看了下源代码

在ArrayList的add操作中
add(int index, Object element)
有一句赋值操作,elementData[index] = element;
所以有可能是两个add操作并发时 把两个element赋值到同一个index位置了
但是在该方法中,有size++ list长度依旧会+2
所以导致其中会有一个是null 没有被赋值

我也是刚看的源码
不知道对你有没有帮助

补充

源代码:
public void add(int index, Object element) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(
"Index: "+index+", Size: "+size);

ensureCapacity(size+1);  // Increments modCount!!
System.arraycopy(elementData, index, elementData, index + 1,
         size - index);
elementData[index] = element;
size++;
}

这个是源码

ensureCapacity(size+1); 这个是给List多加一个存储单元
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
这个是把之前的List,从index的位置开始,往后移动一个位置
elementData[index] = element; 这个就是赋值
size++; 长度加一

造成null主要是由于
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
和 elementData[index] = element;
移动肯定是两次,赋值也是两次,但是赋给了同一个位置

我发现我还是没怎么说清楚
说的有一点小问题
不过不影响你理解
你理解没
要是没理解 我再给你说一遍……

你自己在纸上模拟一下怎么操作的就明白了
很简单的……
当前位置被赋值了
下个位置没有被赋值 变成null了