0

みんな。Collections.synchronizedList()メソッドによって返されるArrayListをテストするために、静的クラスを次のように定義しました。

static class ListWriter implements Runnable { 
    private List<Integer> list; 

    public ListWriter(List<Integer> list) { 
        this.list = list; 
    } 

    public void run() {  // I didn't use synchronized(list) {} block here.
        try { 
            for (int i = 0; i < 20; i++) { 
                list.add(i); 
                Thread.sleep(10); 
            } 
        } catch (Exception e) { 
            e.printStackTrace();
        }
    } 
} 

および以下の試験方法

private static void test1() throws Exception {
    List<Integer> list = Collections.synchronizedList(new ArrayList<Integer>());
    Thread t1 = new Thread(new ListWriter(list)); 
    Thread t2 = new Thread(new ListWriter(list));

    t1.start(); 
    t2.start(); 
    t1.join(); 
    t2.join(); 
    for (int i = 0; i < list.size(); ++i) { 
        System.out.println(list.get(i)); 
    } 
}

結果は通常次のようになります:0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 10 11 11 12 12 13 13 14 14 15 15 16 16 17 17 18 18 19 19

ただし、次のようになる場合もあります。

0 0 1 1 2 3 2 3 4 5 4 5 6 7 6 8 7 9 8 10 9 11 10 12 11 13 12 14 13 15 14 15 16 17 16 17 18 19 18 19

これらの結果は、プロセスがスレッドセーフであることを示していますか?重要なのは、Collection.synchronizedList()メソッドによって返される同期されたArrayListを反復処理するために明示的に必要とされる、書き込みスレッドで同期されたブロックを使用しなかったことです。それで、プロセスはスレッドセーフだと思いますか、それとも同期ブロックを使用する必要がありますか?

4

4 に答える 4

1

出力は非決定論的であり、基盤となるオペレーティング システムのスケジューリング動作に依存します。
あるシーケンスを取得することがあるという事実は、単なる偶然です。リストは によって作成時に同期されるCollections.synchronizedListため、追加の同期は必要ありません。

リストのスレッド セーフ性を大まかにテストするには、両方のスレッドが完了した後で、リストに含まれる要素の数が 40 であることを検証します。

ご指摘のとおり、同時読み取りの場合は、ドキュメントに記載されているように、返されたリストを同期する必要があります

于 2012-08-08T11:49:07.783 に答える
0

スレッドの目的は、独立したタスクを実行することです。そうでない場合は、アクションを調整する必要があり、これがオーバーヘッドになる可能性があります。

驚くかもしれませんが、スレッドが実行される順序も、スレッドがスリープする時間も保証できないということです。2 番目のスレッドが開始する前に、1 つのスレッドを完了まで実行することができます。プログラムまたはマシンがクラッシュし、スレッドが終了しない可能性があります。

これらの結果は、プロセスがスレッドセーフであることを示していますか?

これは、スレッドが独立して実行されていることを示しています。

ポイントは、Collection.synchronizedList() メソッドによって返された同期済み ArrayList を反復処理するために明示的に必要な、書き込みスレッドで同期済みブロックを使用しなかったことです。

この時点でリストを変更するスレッドがないため、これは問題ではありません。

それで、プロセスはスレッドセーフだと思いますか、それとも同期ブロックを使用する必要がありますか?

いいえ。一貫した順序が必要な場合は、スレッドを使用しないでください。よりシンプルで高速になり、毎回同じ結果が得られます。;)

于 2012-08-08T12:01:06.077 に答える
0

メソッドは同期されるため、addコードに余分な同期を追加する必要はありません。数値が順不同になる理由は、2 つのスレッドが停止するThread.sleep()ためであり、これはあまり正確ではありません。そのため、1 つのスレッドがもう一方のスレッドをわずかにオーバーテイクして、2 番目の出力を生成する可能性があります。

を削除するThread.sleep()と、出力のバリエーションがさらに増えます。

于 2012-08-08T11:49:23.307 に答える
0

list同期されるため、余分なコードを追加する必要はありません。

スレッドはプロセッサを取得するときにランダムに実行されるため、出力は毎回同じではない場合があります。

javadocを確認してください。

于 2012-08-08T11:53:06.667 に答える