前不久在给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。所以导致最终记录数不对问题。
不知道删除集合的时候,不做线程控制会不会报错呢,结果是否正确(肯定有问题啊!!领导!!你就坑爹吧!!)
未完,接着本人测试一下其他集合,也希望各位大侠帮忙,分享下集合多线程的经验,不要让小弟挨个集合测试,
本人有测试过了linkedlist , linkedlist的源码分析如下http://blackproof.iteye.com/blog/1583470
所以如果不同步锁的话,肯定会造成链表连接混乱,所以add过程都共享并改变资源header(linkedlist的标志节点)(领导!!你就坑爹吧!!)