xienue 2012-07-07
前不久在给web项目做一个工具包,安全审计。
响应领导号召,为了提高效率不用线程安全的java集合,用如arraylist这样线程不安全的集合,而且自己不加线程控制,哪个servlet都可以向arraylist添加一条记录。
可是在下,怎么想都会有问题,所以多了一个超简单的demo,代码如下:
public static void main(String[] args) { final ArrayList<String> list = new ArrayList<String>(); ExecutorService exec = Executors.newCachedThreadPool(); for(int i=0;i<20000;i++) { Thread t = new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub // synchronized (list) // { list.add("name"); // } // System.out.println("add1"); try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } // synchronized (list) // { list.add("name2"); // } // System.out.println("add2"); } }, i+"name"); exec.execute(t); } try { Thread.sleep(10000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("最终添加记录条数:"+list.size()); }
结果,最终添加记录条数本应该为40000条,实际上是39900多条,总是差个几十条,但是jvm也不报错。
当我把上边那个超简单的demo的synchronized语句打开时,结果为40000条,正确。
不知道jvm是怎么实现滴,看了源码后,感觉是这样滴:
添加记录的add方法,无非也是用index添加到集合中,当多线程同时添加时,假设index为10,第一条线程添加到index为10的值为chineseAV,但是index还没有加一的说,第二条记录就把index为10的值改为japaneseAV。所以导致最终记录数不对问题。
不知道删除集合的时候,不做线程控制会不会报错呢,结果是否正确(肯定有问题啊!!领导!!你就坑爹吧!!)
未完,接着本人测试一下其他集合,也希望各位大侠帮忙,分享下集合多线程的经验,不要让小弟挨个集合测试,
所以如果不同步锁的话,肯定会造成链表连接混乱,所以add过程都共享并改变资源header(linkedlist的标志节点)(领导!!你就坑爹吧!!)