1前書き

この記事では、Javaのコア概念、つまりスレッドのライフサイクルについて詳しく説明します。

スレッド実行中のこれらの状態をよりよく理解するために、簡単な図解図と、もちろん実用的なコードスニペットを使用します。

Javaでスレッドを理解するには、リンクを作成するためのリンク:/java-runnable-vs-extend-thread[この記事]を参照するとよいでしょう。


2 Java

でのマルチスレッド

  • Java言語では、マルチスレッドはスレッドの中心概念によって推進されています** 。ライフサイクルの間、スレッドはさまざまな状態を経ます。

リンク:/uploads/Life

cycle

of

a

Thread

in

Java-768×628.jpg%20768w[]


3 Java

でのスレッドのライフサイクル


java.lang.Thread

クラスには、その潜在的な状態を定義する

static State enum –

が含まれています。どの時点でも、スレッドは次のいずれかの状態にしかなりません。

  1. まだ実行を開始していない


    NEW –


    新しく作成されたスレッド



  2. RUNNABLE –


    実行中または実行の準備ができていますが、待機中です

リソース割り当て



BLOCKED –


を入力または再入力するためのモニタロックの獲得を待機

同期ブロック/メソッド



WAITING –


他のスレッドが特定のスレッドを実行するのを待っている

時間制限のない行動



TIMED

WAITING –__

他のスレッドが実行するのを待っている

指定期間の特定のアクション



TERMINATED –


は実行を完了しました

これらの状態はすべて上の図で説明されています。それでは、これらのそれぞれについて詳細に説明しましょう。


3.1. 新しい


  • NEW


    Thread

    (またはBorn

    Thread

    )は、作成されたがまだ開始されていないスレッドです。**

    start()

    メソッドを使用して開始するまで、この状態のままです。

次のコードスニペットは、新しく作成された

NEW

状態のスレッドを示しています。

Runnable runnable = new NewState();
Thread t = new Thread(runnable);
Log.info(t.getState());

上記のスレッドを開始していないので、メソッド

t.getState()

が出力します。

NEW


3.2. ランナブル

新しいスレッドを作成し、その上で

start()メソッドを呼び出すと、スレッドは

NEW

から

RUNNABLE__状態に移行します。この状態のスレッドは実行中または実行の準備ができていますが、システムからのリソース割り当てを待っています。

マルチスレッド環境では、(JVMの一部である)スレッドスケジューラは各スレッドに一定の時間を割り当てます。そのため、特定の時間実行されてから、制御を他の

RUNNABLE

スレッドに放棄します。

たとえば、前のコードに

t.start()

メソッドを追加して、現在の状態にアクセスしてみましょう。

Runnable runnable = new NewState();
Thread t = new Thread(runnable);
t.start();
Log.info(t.getState());

このコードは、ほとんどの場合、次のように出力を返します。

RUNNABLE

この例では、コントロールが

t.getState()

に達するまでに、まだ

RUNNABLE

状態にあるとは限りません。


Thread-Scheduler

によって即座にスケジュールされたことが起こり、実行が終了することがあります。そのような場合、私達は異なった出力を得るかもしれません。


3.3. ブロックされた

現在実行に適格でないスレッドは、

BLOCKED

状態にあります。モニターロックを待っていて、他のスレッドによってロックされているコードのセクションにアクセスしようとしているときに、この状態になります。

この状態を再現してみましょう。

public class BlockedState {
    public static void main(String[]args) throws InterruptedException {
        Thread t1 = new Thread(new DemoThreadB());
        Thread t2 = new Thread(new DemoThreadB());

        t1.start();
        t2.start();

        Thread.sleep(1000);

        Log.info(t2.getState());
        System.exit(0);
    }
}

class DemoThreadB implements Runnable {
    @Override
    public void run() {
        commonResource();
    }

    public static synchronized void commonResource() {
        while(true) {
           //Infinite loop to mimic heavy processing
           //'t1' won't leave this method
           //when 't2' try to enters this
        }
    }
}

このコードでは:


  1. t1



    t2

    という2つの異なるスレッドを作成しました


  2. t1

    が起動し、同期化された

    commonResource()

    メソッドを入力します.

これは、1つのスレッドだけがそれにアクセスできることを意味します。他のすべての後続
このメソッドにアクセスしようとするスレッドは、それ以降のスレッドからブロックされます。
現在の処理が終了するまで実行


t1

がこのメソッドに入ると、無限のwhileループに保持されます。この

他のすべてのスレッドが実行できないように、重い処理を模倣するだけです。
この方法を入力してください


t2

を起動すると、

commonResource()

メソッドに入ろうとします、

これはすでに

t1によってアクセスされているので、

t2



BLOCKED__状態のままになります

この状態で、

t2.getState()

を呼び出して、出力を次のように取得します。

BLOCKED


3.4. 待っている

  • 他のスレッドが特定のアクションを実行するのを待っているとき、スレッドは

    WAITING

    状態になります。**

    JavaDocsによると

    次の3つのメソッドのいずれかを呼び出すことで、どのスレッドもこの状態に入ることができる


    1. object.wait()


    2. thread.join()

      または


    3. LockSupport.park()


wait()



join()

では、次のセクションでそのシナリオが説明されているため、タイムアウト期間は定義しません。

/java-wait-notify[別のチュートリアル]では、

wait()



notify()

、および

notifyAll()

の使用方法について詳しく説明しています。

今のところ、この状態を再現してみましょう。

public class WaitingState implements Runnable {
    public static Thread t1;

    public static void main(String[]args) {
        t1 = new Thread(new WaitingState());
        t1.start();
    }

    public void run() {
        Thread t2 = new Thread(new DemoThreadWS());
        t2.start();

        try {
            t2.join();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            Log.error("Thread interrupted", e);
        }
    }
}

class DemoThreadWS implements Runnable {
    public void run() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            Log.error("Thread interrupted", e);
        }

        Log.info(WaitingState.t1.getState());
    }
}

ここで私たちがしていることを議論しましょう:


  1. t1

    を作成して開始しました


  2. t1



    t2

    を作成して起動します


  3. t2

    の処理が継続している間に、

    t2.join()

    を呼び出します.


t2

が実行を終了するまで

WAITING

状態の

t1



t1



t2

が完了するのを待っているので、


t2

から

t1.getState()

ご想像のとおり、ここでの出力は次のとおりです。

WAITING


3.5. 時限待ち

別のスレッドが規定の時間内に特定のアクションを実行するのを待っているとき、スレッドは

TIMED

WAITING__状態になります。


https://docs.oracle.com/javase/9​​/docs/api/java/lang/Thread.State.html#TIMED


WAITING[JavaDocsに従って]、スレッドを

TIMED

WAITING

状態にする方法は5つあります。


  1. thread.sleep(ロングミリス)


  2. wait(int timeout)

    または

    wait(int timeout、int nanos)


  3. thread.join(long

    millis


    _)

    _


  4. LockSupport.parkNanos


  5. LockSupport.parkUntil

Javaにおける

wait()



sleep()

の違いについてもっと読むために、リンクを見てください:/java-wait-and-sleep[この記事はこちら]

今のところ、この状態を素早く再現してみましょう。

public class TimedWaitingState {
    public static void main(String[]args) throws InterruptedException {
        DemoThread obj1 = new DemoThread();
        Thread t1 = new Thread(obj1);
        t1.start();

       //The following sleep will give enough time for ThreadScheduler
       //to start processing of thread t1
        Thread.sleep(1000);
        Log.info(t1.getState());
    }
}

class DemoThread implements Runnable {
    @Override
    public void run() {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            Log.error("Thread interrupted", e);
        }
    }
}

ここでは、タイムアウト期間5秒でスリープ状態に入るスレッド

t1

を作成して開始しました。出力は次のようになります。

TIMED__WAITING


3.6. 終了しました

これはデッドスレッドの状態です。実行が終了したとき、または異常終了したときは、

TERMINATED

状態にあります。

私たちはリンクを持っています:/java-thread-stop[専用記事]スレッドを止めるさまざまな方法を議論します。

次の例で、この状態を達成しようとしましょう。

public class TerminatedState implements Runnable {
    public static void main(String[]args) throws InterruptedException {
        Thread t1 = new Thread(new TerminatedState());
        t1.start();
       //The following sleep method will give enough time for
       //thread t1 to complete
        Thread.sleep(1000);
        Log.info(t1.getState());
    }

    @Override
    public void run() {
       //No processing in this block
    }
}

ここでは、スレッド

t1

を開始しましたが、その次のステートメント

Thread.sleep(1000)

によって

t1

が完了するのに十分な時間が与えられます。

TERMINATED


4結論

このチュートリアルでは、Javaにおけるスレッドのライフサイクルについて学びました。


Thread.State

enumで定義されている6つの状態すべてを調べ、簡単な例を使用してそれらを再現しました。

コードスニペットはほとんどすべてのマシンで同じ出力を生成しますが、例外的なケースでは、Thread Schedulerの正確な動作を決定できないため、いくつかの異なる出力が得られる場合があります。

そして、いつものように、ここで使用されているコードスニペットはhttps://github.com/eugenp/tutorials/tree/master/core-java-concurrency[GitHubで利用可能]です。