ArrayList vs Vector - 这是否说明了同步的差异?

时间:2012-05-11 19:49:14

标签: java thread-safety

我正在尝试理解ArrayList和Vector的行为差异。下面的代码片段是否以任何方式说明了同步的差异? ArrayList(f1)的输出是不可预测的,而Vector(f2)的输出是可预测的。我认为f2具有可预测的输出可能只是运气,因为稍微修改f2以使线程进入睡眠状态甚至一个ms(f3)会导致空向量!是什么造成的?

public class D implements Runnable {
   ArrayList<Integer> al;
   Vector<Integer> vl;

   public D(ArrayList al_, Vector vl_) {
      al = al_;
      vl = vl_;
   }

   public void run() {
      if (al.size() < 20)
         f1();
      else
         f2();
   } // 1

   public void f1() {
      if (al.size() == 0)
         al.add(0);
      else
         al.add(al.get(al.size() - 1) + 1);
   }

   public void f2() {
      if (vl.size() == 0)
         vl.add(0);
      else
         vl.add(vl.get(vl.size() - 1) + 1);
   }

   public void f3() {
      if (vl.size() == 0) {
         try {
            Thread.sleep(1);
            vl.add(0);
         } catch (InterruptedException e) {
            System.out.println(e.getMessage());
         }
      } else {
         vl.add(vl.get(vl.size() - 1) + 1);
      }
   }

   public static void main(String... args) {
      Vector<Integer> vl = new Vector<Integer>(20);
      ArrayList<Integer> al = new ArrayList<Integer>(20);
      for (int i = 1; i < 40; i++) {
         new Thread(new D(al, vl), Integer.toString(i)).start();
      }
   }
}

4 个答案:

答案 0 :(得分:4)

回答这个问题:是向量是同步的,这意味着对数据结构本身的并发操作不会导致意外行为(例如NullPointerExceptions等)。因此size()之类的调用在并发情况下使用Vector是完全安全的,但不是ArrayList调用(请注意,如果只有读取访问,ArrayLists也是安全的,我们会尽快遇到问题因为至少有一个线程写入数据结构,例如添加/删除)

问题是,这种低级同步基本上完全没用,你的代码已经证明了这一点。

if (al.size() == 0)
   al.add(0);
else
   al.add(al.get(al.size() - 1) + 1);

这里你想要的是根据当前大小为数据结构添加一个数字(即如果N个线程执行此操作,最后我们希望列表包含数字[0..N))。可悲的是,这不起作用:

假设2个线程在空列表/向量上并发执行此代码示例。以下时间表很可能:

T1: size() # go to true branch of if
T2: size() # alas we again take the true branch.
T1: add(0)
T2: add(0) # ouch

两者都执行size()并返回值0.然后它们进入真正的分支,并且都将0添加到数据结构中。那是不是你想要的。

因此,您无论如何都必须在业务逻辑中进行同步,以确保size()add()以原子方式执行。因此,几乎在任何情况下,向量的同步都是无用的(与现代JVM上的一些声明相反,无竞争锁的性能损失完全可以忽略不计,但Collections API更好,所以为什么不使用它)

答案 1 :(得分:0)

In The Beginning(Java 1.0)中有“同步向量”。

这可能会导致巨大的性能损失。

因此在Java 1.2之后添加了“ArrayList”和朋友。

您的代码说明了首先使矢量同步的基本原理。但是大部分时间它都是不必要的,而其他时间大部分时间都是以其他方式做得更好。

... IMHO

PS: 一个有趣的链接:

http://www.coderanch.com/t/523384/java/java/ArrayList-Vector-size-incrementation

答案 2 :(得分:0)

向量是线程安全的。 ArrayLists不是。这就是ArrayList比矢量更快的原因。 以下链接有很好的信息。

http://www.javaworld.com/javaworld/javaqa/2001-06/03-qa-0622-vector.html

答案 3 :(得分:0)

  

我正在尝试理解ArrayList的行为差异   和一个矢量

Vectorsynchronized,而ArrayList则不是。 ArrayList不是线程安全的。

  

以下代码段是否以任何方式说明了其中的区别   同步?

没有区别,因为只有Vectorsunchronized