こんにちは!今日も引き続きマルチスレッドについて話します。Thread クラスとそのいくつかのメソッドがどのように機能するかを見てみましょう。以前は、クラス メソッドを学習するとき、ほとんどの場合、「メソッドの名前」 -> 「何を行うか」というように単純に記述していました。
これは Thread メソッドでは機能しません :) そのロジックはより複雑で、いくつかの例がなければ理解することは不可能です。
素晴らしい追加素材として役立ちます! 最後に、メソッドの概要を説明した後、このコースでさらに何を行うかについて正確に説明します:) 頑張ってください!
Thread.start() メソッド
繰り返しから始めましょう。覚えているかもしれませんが、クラスからクラスを継承しThread
、そのメソッドをオーバーライドすることでスレッドを作成できますrun()
。しかし、もちろん、それはひとりでに始まるわけではありません。これを行うには、オブジェクトのメソッドを呼び出しますstart()
。 前の講義の例を思い出してください。
public class MyFirstThread extends Thread {
@Override
public void run() {
System.out.println("Выполнен поток " + getName());
}
}
public class Main {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
MyFirstThread thread = new MyFirstThread();
thread.start();
}
}
}
注意:スレッドを開始するには、!start()
ではなくrun()
これは、特にマルチスレッドを初めて学習する場合に起こりやすい間違いです。この例で、オブジェクトのメソッドをrun()
の代わりにstart()
、結果は次のようになります。
public class Main {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
MyFirstThread thread = new MyFirstThread();
thread.run();
}
}
}
スレッド 0 スレッド実行 スレッド 1 スレッド実行 スレッド 2 スレッド実行 スレッド 3 スレッド実行 スレッド 4 スレッド実行 スレッド 5 スレッド実行 スレッド 6 スレッド実行 スレッド 7 スレッド実行 スレッド 8 スレッド実行 スレッド 9 スレッド実行 出力シーケンスを見てください。すべてが厳密に順序通りに進んでいます。奇妙ですよね?私たちはこれに慣れていません。なぜなら、スレッドが起動および実行される順序が、オペレーティング システム内のスーパーインテリジェンスであるスレッド スケジューラによって決定されることをすでに知っているからです。たぶん私はただ幸運でしたか?もちろん、それは運の問題ではありません。プログラムをさらに数回実行することで、これを確認できます。重要なのは、メソッドの直接呼び出しはrun()
マルチスレッドとは何の関係もないということです。この場合、プログラムはメインスレッド、つまりメソッドが実行されるスレッドで実行されますmain()
。コンソールに 10 行を連続して出力するだけです。10 個のスレッドは開始されません。したがって、将来のために思い出して、常に自分自身をチェックしてください。それを実行したい場合はrun()
、それを呼び出しますstart()
。次へ移りましょう。
Thread.sleep() メソッド
現在のスレッドの実行をしばらく一時停止するには、 を使用しますsleep()
。 このメソッドはsleep()
パラメータとしてミリ秒数、つまりスレッドをスリープ状態にする必要がある時間を受け取ります。
public class Main {
public static void main(String[] args) throws InterruptedException {
long start = System.currentTimeMillis();
Thread.sleep(3000);
System.out.println(" - Сколько я проспал? \n - " + ((System.currentTimeMillis()-start)) / 1000 + " секунды");
}
}
コンソール出力: - どのくらい寝ましたか? - 3 秒 注意: このメソッドsleep()
は静的です。現在のスレッドをスリープ状態にします。つまり、現時点で動作しているものです。もう 1 つの重要なニュアンスは、スリープ状態のフローが中断される可能性があることです。この場合、プログラム内で例外が発生しますInterruptedException
。以下に例を見ていきます。ところで、スレッドが「目覚めた」後はどうなるでしょうか? 中断したところからすぐに実行を続行しますか? いいえ。スレッドがウェイクアップした後、引数として渡された時間が経過すると、スレッドは実行可能Thread.sleep()
状態に入ります。ただし、これはスレッド スケジューラがスレッドを実行することを意味するものではありません。他の「スリープ状態ではない」スレッドが優先され、「新たに目覚めた」スレッドは少し遅れても引き続き動作する可能性があります。「目覚めたからといって、その瞬間から仕事を続けるわけではない」ということを必ず覚えておいてください。
Thread.join() メソッド
このメソッドは、join()
別のスレッドが完了するまで現在のスレッドの実行を一時停止します。2 つのスレッドがある場合、t1
とt2
、そして次のように書きます -
t1.join()
t2
t1 が作業を完了するまでは作業を開始しません。この方法join()
を使用すると、スレッドの実行順序を保証できます。join()
例を使用して 作業を見てみましょう。
public class ThreadExample extends Thread {
@Override
public void run() {
System.out.println("Начало работы потока " + getName());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Поток " + getName() + " завершил работу.");
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
ThreadExample t1 = new ThreadExample();
ThreadExample t2 = new ThreadExample();
t1.start();
/*Второй поток t2 начнет выполнение только после того, How будет завершен
(or бросит исключение) первый поток - t1*/
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
t2.start();
//Главный поток продолжит работу только после того, How t1 и t2 завершат работу
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Все потоки закончor работу, программа завершена");
}
}
単純なクラスを作成しましたThreadExample
。そのタスクは、作業の開始に関するメッセージを画面に表示し、その後 5 秒間眠りに落ち、最後に作業の完了を通知することです。何も複雑なことはありません。メインロジックはクラスに含まれていますMain
。コメントを見てください。このメソッドを使用して、join()
スレッドの実行順序を正常に制御しています。トピックの冒頭を覚えていると、スレッド スケジューラがこれを実行しました。彼は自分の裁量でそれらを毎回異なる方法で起動しました。ここでは、このメソッドを使用して、最初にスレッドが起動して実行されt1
、次にスレッドが起動t2
され、その後にのみプログラム実行のメイン スレッドが起動されるようにしました。どうぞ。実際のプログラムでは、スレッドの実行を中断する必要がある状況に遭遇することがよくあります。たとえば、スレッドは実行中ですが、特定のイベントまたは条件が満たされるのを待っているとします。こうなると止まります。のようなメソッドがあればおそらく論理的でしょうstop()
。ただし、すべてがそれほど単純ではありません。かつて、Thread.stop()
Java にはスレッドの作業を中断できるメソッドが実際に存在していました。しかし、後に Java ライブラリから削除されました。Oracle のドキュメントを参照すると、非推奨としてマークされていることがわかります。なぜ?追加の作業を行わずに単に流れを止めただけだからです。たとえば、スレッドはデータを操作し、その中の何かを変更することができます。そして彼はstop()
仕事の途中で突然倒れてしまいました - そしてそれだけでした。正しいシャットダウンも、リソースの解放も、エラー処理さえも行われませんでした。これらはいずれも起こりませんでした。この方法はstop()
、大げさに言えば、その経路にあるすべてのものを単に破壊しただけです。その動作は、コンピューターの電源を切るためにソケットからプラグを抜く方法にたとえることができます。はい、期待通りの結果を得ることができます。しかし、数週間後にはコンピューターがこれに対して「ありがとう」と言ってくれなくなることは誰もが理解しています。このため、Java でスレッドを中断するロジックが変更され、特別なメソッドが使用されるようになりましたinterrupt()
。
Thread.interrupt() メソッド
スレッド上でメソッドを 呼び出すとどうなりますかinterrupt()
? 2 つのオプションがあります:
- その時点でオブジェクトが待機状態にあった場合 (たとえば、
join
または )sleep
、待機は中断され、プログラムは をスローしますInterruptedException
。 - その時点でスレッドが動作状態にあった場合、オブジェクトのブール フラグが設定されます
interrupted
。
Thread
特別なメソッドがあります - boolean isInterrupted()
。メインコースの講義の時計の例に戻りましょう。便宜上、少し簡略化してあります。
public class Clock extends Thread {
public static void main(String[] args) throws InterruptedException {
Clock clock = new Clock();
clock.start();
Thread.sleep(10000);
clock.interrupt();
}
public void run() {
Thread current = Thread.currentThread();
while (!current.isInterrupted())
{
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("Работа потока была прервана");
break;
}
System.out.println("Tik");
}
}
}
私たちの場合、時計は毎秒動き始めます。10 秒目でクロックの流れを中断します。すでにご存知のとおり、割り込みしようとしているスレッドが待機状態のいずれかにある場合、結果は になりますInterruptedException
。このタイプの例外はチェック例外であるため、簡単にキャッチしてプログラム終了ロジックを実行できます。それが私たちがやったことです。 Tik Tik Tik Tik Tik Tik Tik Tik Tik スレッドの作業が中断されました これで、 クラス の主なメソッドの紹介は終わりです 。知識を強化するには、マルチスレッドに関する次のビデオ講義をご覧ください。 Thread
GO TO FULL VERSION