3

我试图了解 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

4 回答 4

4

回答这个问题:是的,向量是同步的,这意味着对数据结构本身的并发操作不会导致意外行为(例如 NullPointerExceptions 或其他东西)。因此,在并发情况下,like 调用size()对于 a 是完全安全的Vector,但对于 an 则不是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 更好,所以为什么不使用它)

于 2012-05-11T19:58:42.383 回答
0

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

这可能会对性能造成巨大影响。

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

您的代码首先说明了使向量同步的基本原理。但在大多数情况下,这根本是不必要的,在其余的大部分时间里,最好以其他方式完成。

恕我直言...

PS:一个有趣的链接:

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

于 2012-05-11T19:52:21.327 回答
0

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

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

于 2012-05-11T19:56:45.437 回答
0

我试图了解 ArrayList 和 Vector 的行为差异

VectorsynchronizedArrayList不是。ArrayList不是线程安全的。

以下片段是否以任何方式说明了同步的差异?

没有区别,因为Vector只有sunchronized

于 2012-05-11T19:57:39.590 回答