public class test14  {

private static List<Integer> arraylist=Collections.synchronizedList(new ArrayList<Integer>());
// private static List<Integer> arraylist=new ArrayList<>();


public static void main(String[] args) {

for(int i=0;i<2000;i++)
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
while(!Thread.interrupted()&&arraylist.size()<10000){
arraylist.add(0);
}
}
}).start();

try {
TimeUnit.MILLISECONDS.sleep(200);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("size: "+arraylist.size());
}
}
输出:size: 10011网上有个例子证明ArrayList是非线程安全的:
http://m.blog.csdn.net/article/details?id=52163131  ,
大部分的资料只是说ArrayList是非线程安全的,如果要使其线程安全,可以使用Collections.synchronizedList()对其进行包装,那么我模仿例子自己写了一段代码想验证一下,可是得到的输出却不是size==10000
既然包装以后是线程安全的容器,为什么会出现这样的情况呢?我也翻看了Collections.synchronizedList()的相关源码,发现size()和add()都是有同步的,这让我更加不解了

解决方案 »

  1.   

    while(!Thread.interrupted()&&arraylist.size()<10000){   //有20个线程在等待调用size,第一个线程调用了size其他等待,size是9999通过,准备调用add,但是第二个线程已经调用size了,第一个线程的add方法就等待了,所以会出现还没add其他的就调用size了
                            arraylist.add(0);
     }
      

  2.   


    哦,有些明白了,那是不是说,即使我们使用JDK里面线程安全的容器,如果要套用自己的其他方法的时候,代码也不能随便写,也要考虑同步问题?仿照书上写成double check形式,测试好像没问题,但我不确定是否正确,而且这样写,直接用普通的ArrayList也能得到size=10000, 不过特别的慢,这又是为什么呢public static void main(String[] args) {

    for(int i=0;i<2000;i++)
    new Thread(new Runnable() {
    @Override
    public void run() {
    // TODO Auto-generated method stub
    while(!Thread.interrupted()){
    if(arraylist.size()<10000)
    synchronized(arraylist){
    if(arraylist.size()<10000)
    arraylist.add(0);
    }
    }
    }
    }).start();

    try {
    TimeUnit.MILLISECONDS.sleep(200);
    } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    System.out.println("size: "+arraylist.size());
    }
      

  3.   


    即使我们使用JDK里面线程安全的容器,如果要套用自己的其他方法的时候,代码也不能随便写,也要考虑同步问题?