web-dev-qa-db-ja.com

Thread.joinとSynchronizedの違いは何ですか?

マルチスレッドアプリケーションでThread.join()を使用する場合とsynchronizationを使用する場合がわかりません。

私によると、どちらも他のスレッドによって実行が行われるのをブロックまたは待機します。
この例では、次のように10個のA、10個のB、10個のCを順番に出力する必要があります。

1  : A
2  : A
3  : A
4  : A
5  : A
6  : A
7  : A
8  : A
9  : A
10 : A
1  : B
2  : B
3  : B
4  : B
5  : B
6  : B
7  : B
8  : B
9  : B
10 : B
1  : C
2  : C
3  : C
4  : C
5  : C
6  : C
7  : C
8  : C
9  : C
10 : C
----ProGraM ENDS----

例はここから始まります

class SyncTest extends Thread 
{   
    StringBuffer sb;

    public SyncTest(StringBuffer sb) 
    {
        this.sb = sb;   
    }

    public void run()
    {
        synchronized(sb) 
        {
            for(int i=1;i<=10;i++){
                System.out.println(i+" : "+sb.charAt(0));
            }
            sb.setCharAt(0, (char) (sb.charAt(0)+1));
        }
    }

    public static void main(String [] args) throws InterruptedException
    {
        StringBuffer sb = new StringBuffer("A");
        Thread t1=new SyncTest(sb);
        Thread t2=new SyncTest(sb);
        Thread t3=new SyncTest(sb);

        t1.start();

        t2.start();

        t3.start();

        Thread.sleep(1000);

        System.out.println("----ProGraM ENDS----");
    }
}

ここで、出力は10 A、10 B、10Cの順であることがわかります。ただし、synchronizedブロックの代わりにThread.joinを使用して、次のような同じ出力を取得することもできます。

public void run()
    {
        //removed synchronized statement...

            for(int i=1;i<=10;i++){
                System.out.println(i+" : "+sb.charAt(0));
            }
            sb.setCharAt(0, (char) (sb.charAt(0)+1));

    }

    public static void main(String [] args) throws InterruptedException
    {
        StringBuffer sb = new StringBuffer("A");
        Thread t1=new SyncTest(sb);
        Thread t2=new SyncTest(sb);
        Thread t3=new SyncTest(sb);

        t1.start();
        t1.join();
        t2.start(); // wait for t1 to complete
        t2.join();
        t3.start(); // wait for t2 to complete
        t3.join(); 

                     // wait for t3 to complete
        System.out.println("----ProGraM ENDS----");
    }

JavaのマルチスレッドでThread.joinを使用する場合とsynchronizationを使用する場合など、これら2つの手法の使用に関する混乱を解消できますか。

11
JPG

Thread.join()はスレッドが完全に終了するのを待ちますが、synchronizedブロックを使用すると、2つのスレッドが同じコードを同時に実行するのを防ぐことができます。

それらは異なる目的を果たすので、一般的にどちらを使用するかをアドバイスするのは難しいです。コードなど、2つの違いが最小限である例を見つけることはめったにありません。

そうは言っても、最初の例では、出力がアルファベット順になる保証はありません。どのスレッドが最初にsynchronizedブロックに到達するかを確認することはできません。したがって、この特定のケースでは、join()が最も適切です。

15
Duncan Jones

thread.join()は、結合されたスレッドが完了するまで現在のスレッドの実行を停止します。.正しくコメントしました。:)

Synchronizationは、multipleスレッドが同じインスタンスでコードの同期された部分を実行するのを防ぎます。

5
TheLostMind

synchronizedキーワードは、スレッドが互いに踏まないようにするロックメカニズムを有効にします。 Javaドキュメントでは、これを「スレッドの干渉とメモリの整合性エラーを防ぐ」方法として説明しています。

join()を使用すると、スレッドがjoinを呼び出すとすぐに、joinを呼び出したスレッドが終了しない限り、現在のスレッド(実行中のスレッド)が実行されないようになります。下の図は、これをよりよく視覚化するのに役立つと思います。

enter image description here

ソース

4
Ali Gajani

join()がないと、スレッドは並行して実行され、OSタイムスライス(最初に開始する)に依存します。 join()を使用すると、スレッドは直列に実行されます。例:両方がjoin()メソッドを呼び出す2つのスレッドがあるとします。

_MyThread t1 = new MyThread();
MyThread t2 = new MyThread();

t1.join(); // this will be start first.
t2.join(); // this will be start only after above.
_

join()メソッドがないと、_t1_と_t2_のいずれかを最初に開始できます。保証はありません。

synchronizedステートメント/キーワードはスレッドの監視に使用されるため、一度に1つのスレッドのみがその同期されたメソッド/変数にアクセスできます。 join()を使用するかどうかは関係ありません。

synchronizedjoin()とともに使用すると、スレッド_t1_が最初にのみアクセスできることが保証されます。 synchronizedがないと、_t1_と_t2_の両方のスレッドがいつでもアクセスできますが、これらのスレッドは開始して終了します。 join()のために直列になっています。

2
Ashish Rawat

それらは明らかに同じではありませんが、同じ目的(アクセス/実行のシリアル化)で使用される場合、同期ブロックは、その使用法が特定のスレッドインスタンスに依存しないため、結合を使用するよりも柔軟なバージョンと見なすことができます実行をシリアル化したい。

さらに、同期ブロックでは、共有データブロックの概念が結合よりも強調されます。

1
stdout

簡単な例:

いくつかのスレッドがいくつかの値を置く静的な文字列テーブルがあります。テーブルは「空」で初期化されます。テーブルには静的インデックスを使用してアクセスします。スレッドが値を入力すると、静的インデックスがインクリメントされます。

スレッドを同期すると、スレッドによって設定された値が別のスレッドによってオーバーライドされないようになります。

スレッドで結合を使用する場合、最初に結合されたスレッドのみが値をテーブルに配置する機会があります。他のスレッドは待機しているが、インデックスがインクリメントされていることを知っているため、テーブルにアクセスできません(nullポインタ例外) 。そのため、Joinは他のスレッドを役に立たなくしました。

この例では、同期メソッドを含む同じインスタンスのスレッドを使用します。

0
Java Main