3

ArrayListとVectorの動作の違いを理解しようとしています。次のスニペットは、同期の違いを何らかの形で示していますか?ArrayList(f1)の出力は予測できませんが、Vector(f2)の出力は予測可能です。f2をわずかに変更してスレッドをms(f3)でもスリープ状態にすると、空のベクトルが発生するため、f2に予測可能な出力があるのは幸運かもしれません。何が原因ですか?

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など)を引き起こさないことを意味します。したがって、のような呼び出しは、並行状況でsize()は完全に安全ですが、 (読み取りアクセスのみがある場合はArrayListsも安全であることに注意してください。少なくとも、1つのスレッドがデータ構造に書き込むとすぐに問題が発生します(追加/削除など))。VectorArrayList

問題は、この低レベルの同期は基本的に完全に役に立たず、コードはすでにこれを示しているということです。

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)には、「同期されたベクトル」がありました。

これは、潜在的に巨大なパフォーマンスヒットを伴いました。

したがって、Java1.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の動作の違いを理解しようとしています

Vectorsynchronizedない間ですArrayListArrayListスレッドセーフではありません。

次のスニペットは、同期の違いを何らかの形で示していますか?

だけなので違いはありませVectorsunchronized

于 2012-05-11T19:57:39.590 に答える