for循环构造10个线程删除同一个集合中的数据,理论上只能删除100000次。但是运行完发现,输出的删除次数108494次,其中很多数据都是被多个线程删除,比如下面的输出片段:

  17ticket NO,35721
  14ticket NO,35699
  11ticket NO,35721
  18ticket NO,35721
  17ticket NO,35729
  11ticket NO,35729
  14ticket NO,35729
  17ticket NO,35729
  14ticket NO,35734
  17ticket NO,35734
  13ticket NO,35721

  可以看到35721,35729都被多个线程删除。这事实上是出现了脏读。解决的办法是加锁,使得同一时刻只有1个线程对ArrayList做操作。

  修改代码,synchronized关键字,让得到锁对象的线程才能运行,这样确保同一时刻只有一个线程操作集合。

    final List<String> tickets = new ArrayList<String>();
    for (int i = 0; i < 100000; i++) {
       tickets.add("ticket NO," + i);
    }
    System.out.println("start1...");
    final Object lock=new Object();
    for (int i = 0; i < 10; i++) {
       Thread salethread = new Thread() {
           public void run() {
               while (true) {
                   synchronized(lock)
                   {
                     if(tickets.size()>0)
                       System.out.println(Thread.currentThread().getId()+ tickets.remove(0));
                     else
                        break;
                   }
               }
           }
       };
       salethread.start();
    }

  这样得到的结果是准确的了。

  当然,不使用synchronized关键字,而直接使用vector或者Collections.synchronizedList 也是同样效果:

    final List<String> tickets =java.util.Collections.synchronizedList(new ArrayList<String>());
    final List<String> tickets =new Vector<String>();

  vector和Collections.synchronizedList 都是线程同步的,避免的脏读的出现。