序文
Java のスレッド ライフ サイクルは、マルチスレッド開発の中核となる概念です。効率的でエラーのないマルチスレッド プログラムを作成するには、スレッドのライフサイクルとスレッドの状態遷移を理解することが重要です。
1. スレッドのライフサイクル
Java スレッドには主に次の状態があり、これらは Thread.State 列挙クラスで定義されます。
-
新しい状態 (New) : 新しいスレッド インスタンスを作成すると、スレッドは新しい状態になります。この時点では、
start()
スレッドのメソッドは呼び出されておらず、スレッド オブジェクトの実行はまだ開始されていません。この状態では、Java 仮想マシン (JVM) がこのスレッドに必要なメモリを割り当てています。Thread t = new Thread(); // 线程此时处于New状态
-
準備完了状態 (実行可能) : スレッド オブジェクトが
start()
メソッドを呼び出すと、スレッドは準備完了状態になります。準備完了状態のスレッドは、CPU タイム スライスを取得した後に実行を開始できます。この状態のスレッドは実行可能なスレッド プール内にあり、CPU を使用する権利を取得するためにスレッド スケジューリングによって選択されるのを待っています。t.start(); // 线程此时处于Runnable状态
-
実行状態 (Running) : スレッドは CPU タイム スライスを取得した後、実行状態に入り、
run()
メソッド内のコードの実行を開始します。コード実行の実際の速度と効率は、プロセッサの速度とマルチコア プロセッサのコアの数に関係していることに注意してください。public void run() { System.out.println("Thread is running."); } // 如果此时这个方法正在执行,那么线程就处于Running状态
-
ブロック状態 (ブロック) : スレッドが内部オブジェクト ロックを取得しようとしている (つまり、ブロックに入っている
synchronized
) ときに、そのロックが他のスレッドによって保持されている場合、スレッドはブロック状態に入ります。ブロック状態のスレッドは、ロックが解放されると準備完了状態になります。synchronized(object) { // 如果此时object的锁被其他线程持有,那么线程就处于Blocked状态 }
-
待機中
wait()
: スレッドは、独自のメソッド、join()
メソッド、またはメソッドを呼び出すLockSupport.park()
か、別のスレッドのメソッドを呼び出すことによってjoin()
待機状態に入ることができます。待機状態のスレッドには CPU タイム スライスが割り当てられず、他のスレッドによって明示的にウェイクアップされることによってのみ準備完了状態に入ることができます。t.wait(); // 线程此时处于Waiting状态 t.join(); // 线程此时处于Waiting状态
-
時間指定待機状態 (時間指定待機) : スレッドが指定された待機時間で
sleep(long ms)
、wait(long ms)
、join(long ms)
、LockSupport.parkNanos()
、LockSupport.parkUntil()
などのメソッドを呼び出すと、スレッドは時間指定待機状態に入ります。タイムアウトが経過すると、スレッドは自動的に準備完了状態に戻ります。Thread.sleep(1000); // 线程此时处于Timed Waiting状态
-
終了状態:
run()
スレッドのメソッドが実行されるか、スレッドが中断されると、スレッドは終了状態になります。この状態では、スレッドはすべての作業を完了しています。// 当run()方法执行完毕,线程处于Terminated状态 public void run() { System.out.println("Thread is running."); }
これらの状態間の遷移は、さまざまなメソッドを呼び出すことで実現されます。次に、これらの状態遷移の詳細を見ていきます。
2. スレッドの状態遷移
スレッドの状態の遷移は非常に重要な部分であり、状態間の遷移を理解することは、スレッドの動作をより深く理解し、習得するのに役立ちます。次に、Java のさまざまなスレッドの状態の遷移を見てみましょう。
-
新しい状態から準備完了状態へ: スレッド オブジェクトが作成されると、新しい状態になります。このとき、
start()
スレッドオブジェクトのメソッドを呼び出すことで、スレッドは準備完了状態となり、システムのスレッドスケジューラによるスケジュールを待つことができます。Thread t = new Thread(); // 新建状态 t.start(); // 调用start()方法,线程进入就绪状态
-
準備完了状態から実行状態へ: スレッド スケジューラは準備完了キューからスレッドを選択してそれに CPU リソースを割り当て、スレッドは準備完了状態から実行状態に変わります。
-
実行状態は準備完了状態に変わります。実行状態のスレッドが
yield()
メソッドを呼び出すか、スレッドの実行時間がシステムによって指定されたタイムスライスを超えると、スレッドは CPU リソースを解放し、実行状態から準備完了状態に変わります。準備完了状態になり、システムが再度スケジュールを設定するまで待ちます。Thread.yield(); // 调用yield()方法,线程从运行状态进入就绪状态
-
実行状態からブロック状態へ: 実行状態のスレッドが他のスレッドによって保持されているオブジェクト ロックを取得しようとすると、スレッドはブロック状態になります。
synchronized(object) { // 如果此时object的锁被其他线程持有,那么线程就从运行状态进入阻塞状态 }
-
ブロック状態から準備完了状態へ: ブロック状態のスレッドが他のスレッドによって解放されたオブジェクト ロックを取得すると、スレッドはブロック状態から準備完了状態に変わり、システムが再びスケジュールするのを待ちます。
-
実行状態から待機状態へ: 実行状態のスレッドがまたは
wait()
メソッドを呼び出すと、スレッドは待機状態に入ります。待機状態にあるスレッドは、準備完了状態に戻るために他のスレッドからの通知に依存する必要があります。join()
LockSupport.park()
t.wait(); // 调用wait()方法,线程从运行状态进入等待状态 t.join(); // 调用join()方法,线程从运行状态进入等待状态
-
待機状態から準備完了状態へ: 待機状態のスレッドが他のスレッドによって呼び出されるか起動されるか、他のスレッドによって中断されるか、待機時間が経過すると、スレッドは待機状態から準備完了状態に変わります
notify()
。notifyAll()
t.notify(); // notify()方法被调用,线程从等待状态进入就绪状态
-
実行状態がタイムアウト待機状態に変わります。実行状態のスレッドが
sleep()
、タイムアウト パラメータを指定して 、wait()
、join()
、またはメソッドを呼び出すと、スレッドはタイムアウト待機状態に入ります。LockSupport.parkNanos()
LockSupport.parkUntil()
Thread.sleep(1000); // 调用sleep()方法,线程从运行状态进入超时等待状态
-
タイムアウト待ち状態から準備完了状態へ: タイムアウト待ち状態のスレッドの待ち時間が満了するか、他のスレッドによってウェイクアップまたは中断されると、スレッドはタイムアウト待ち状態から準備完了状態に変わります。
-
任意の状態から終了状態へ: スレッドがタスクを完了するか、例外により終了すると、終了状態に入ります。
上記のスレッドの状態遷移を理解することで、スレッドの動作メカニズムをより深く理解し、マルチスレッドプログラミングの理論的基礎を得ることができます。
3. スレッドのライフサイクルの例
次の Java コード例は、スレッドの作成から終了までのプロセス全体を示しています。
// 创建一个继承了Thread类的ExampleThread类
class ExampleThread extends Thread {
private Object lock; // 创建一个私有的Object对象,它将在同步代码块中被使用作为锁
// 构造函数,接受一个Object类型的参数
public ExampleThread(Object lock) {
this.lock = lock; // 将传入的对象赋值给lock
}
// 重写Thread类的run方法
@Override
public void run() {
// 同步代码块,只有获取到lock对象的锁才能执行
synchronized(lock) {
try {
// 输出线程名和状态
System.out.println(Thread.currentThread().getName() + " is running");
// 让线程睡眠1秒,此时线程进入TIMED_WAITING状态
Thread.sleep(1000);
// 输出线程名和状态
System.out.println(Thread.currentThread().getName() + " is waiting");
// 调用wait()方法,线程释放lock锁,进入WAITING状态
lock.wait();
// 线程被唤醒,获取到lock锁,输出线程名和状态
System.out.println(Thread.currentThread().getName() + " is running again");
} catch (InterruptedException e) {
// 线程被中断,输出线程名和状态,然后线程将结束
System.out.println(Thread.currentThread().getName() + " is interrupted and will terminate");
}
}
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
// 创建一个共享的锁对象
Object lock = new Object();
// 创建一个新的线程(NEW状态)
Thread t1 = new ExampleThread(lock);
System.out.println(t1.getName() + " is created");
// 启动新的线程(READY/RUNNABLE状态)
t1.start();
// 让主线程睡眠2秒,这样新线程就可以先运行
Thread.sleep(2000);
// 唤醒等待的线程(将进入READY/RUNNABLE状态)
synchronized(lock) {
lock.notify();
}
// 让主线程再睡眠1秒,这样被唤醒的线程可以完成运行
Thread.sleep(1000);
}
}
このコード例は、Java スレッドの作成 (NEW 状態)、準備完了および実行 (READY/RUNNABLE 状態)、待機 (WAITING 状態)、ウェイクアップされて再び実行、そして最終的に終了 (TERMINATED) までのプロセス全体を示しています。州)。
アプリケーションのパフォーマンスを最適化します。
結論
上記の内容が Java スレッドのライフサイクルを理解するのに役立つことを願っています。スレッドのライフサイクルを理解することは、並行プログラムの作成やマルチスレッド プログラミングにとって非常に重要です。覚えておいてください、学ぶための最良の方法は実践することです。したがって、スレッドのライフサイクルの各段階をより深く理解するために、上記のコードを自分で試してみることをお勧めします。