記事のディレクトリ
1つは、スレッドの基本概念です。
1.スレッドとは何ですか?プロセスとは何ですか?
スレッドとプロセスの退屈な概念を説明すると、プロセスはリソース割り当ての基本単位であり、スレッドはCPUスケジューリングの最小単位です。そのような答えは文字通りで抽象的で理解しにくいので、私が見た例を挙げましょう。
プロセスがデータと情報を運ぶ列車である場合、スレッドはキャリッジです。
列車が複数の車を持つことができるのと同じように、プロセスは複数のスレッドを持つことができます。
列車が故障した場合、多くの場合、他の列車の運行に影響を与えないか、影響は限定的です。車両が故障すると、列車が走り続けることが難しくなります。このように、プロセスがクラッシュした後、プロテクトモードの他のプロセスへの影響は限定的ですが、スレッドがハングすると、プロセスがクラッシュする可能性が高いことを理解するのは簡単です。したがって、マルチプロセスはマルチスレッドよりも堅牢です
スレッドとは何か、プロセスとは何かを理解している場合、2つの違いは何ですか?
2.スレッドとプロセスの詳細な説明(警告を思いとどまらせる)
まず、スレッドとプロセスの概要を比較します。プロセスとスレッドは、どちらもCPUの稼働時間の説明であり、実行中のプログラム命令の説明でもありますが、粒度は異なります。
注:次の大きな概念が表示されます。眠い場合はスキップしてください。
まず、プログラム実行の背景を見てみましょう。
私たちのコンピュータは、実際にはCPU + RAM(メモリ)+周辺機器(グラフィックカード、光学ドライブなど)で構成されています。プログラムの実際の動作は実際に処理されます。 CPU + RAMの組み合わせによる。
CPUの算術演算装置が速すぎるという事実も無視できません。[コンピュータの原理] -CPUの基本的な紹介で、ALU(算術演算装置)はレジスタよりもはるかに高い計算能力を持っていると述べました。バッファ領域とRAMは言うまでもありません。では、複数のタスクを実行する必要がある場合はどうなりますか?最初のタスクを実行してから2番目のタスクを実行する必要がありますか?この場合、CPUの実際の実行時間は、実際には待機時間と1桁の差があります。それでもわからない場合は、在学中に宿題をしていたとき、宿題の本を書く速度が脳の計算の速さに追いつかないので、脳がすでに1 + 1 = 2と計算された場合、おそらく手はプラス記号を書き終えたばかりであり、この時点で、計算を担当する脳の部分が休み始め、次の計算を待ちます。計算に1ms、書き込みに1sかかる場合があります。
知っておく必要のある別の事実があります。機能を実現するためにプログラムコードを実行するプロセスでは、CPUを取得するときに、関連するリソースを配置し、コンピュータがCPUを必要とするタスクを決定するのを待つ必要があります。このとき、PC(命令カウンタ)がタスクコードを指し、CPUが命令を取得して実行を開始します。
したがって、直列接続は実際には次のようになります。CPUはプロセスAを呼び出し、その中の命令をフェッチし、Aの実行を開始し、Aの結果を保存します(コンテキストはここでは繰り返されません)。次に、実行を待機している次のプロセスBに転送し、Bの実行を開始します。もちろん、CPUによってプログラムBに割り当てられたタイムスライスが使い果たされた場合、彼は一時的に実行結果をコンテキストに保存し、スイッチアウトの準備をして、CPUが再び幸運になるのを待ちます。
背景の物語は終わったので、プロセスとスレッドは何ですか?
処理するこれは、CPUコンテキストスイッチング間のプログラム実行の一部であり、現在CPUで実行されているプログラムの説明です。CPU実行時間の説明とも言えます。
何についてのスレッド?
プロセスの粒度が大きすぎるため、実行ごとにコンテキストの切り替えが必要です。ソフトウェアをアプリケーションプログラムと見なす場合、ソフトウェアの実行は1つのロジックだけで構成することはできず、複数のプログラムセグメントを分岐することによって実現する必要があります。その後、プログラムを実行すると、プログラムAの小さなコードになり、すぐにCPUを使用する権利を取得します。このとき、CPUは小さな部分aの命令をロードし、小さな部分aの実行を開始します。aセクションの実行が完了したら、bセクションの命令実行に切り替えます。最後に、すべてのコードセグメントが実行されたら、プログラムAの計算結果を保存し、プログラムAを終了して、プログラムBを起動します。ここで、プログラムAとプログラムBの間の切り替え時間は、コードセグメントaとコードセグメントbの間の切り替えよりもはるかに長くなります。コードシートaとコードセグメントbの時間の合計が、プログラムAの実行時間です。ここでのコードセグメントaとbは実際にはスレッドです。これらは、プロセスAのコンテキストを共有し、CPUによって短い期間で完了したタスクを記述します。
この時点で、プロセスが一定期間のCPU処理の動作状態の記述であり、スレッドがこの期間の各詳細な作業内容の記述であることを理解するのは難しいことではありません。本質的に、プロセスとスレッドの違いはCPUの稼働時間です。この段落で説明されている粒度は異なります。
3.デーモンスレッド(デーモンスレッド)
ユーザースレッドとは異なり、デーモンスレッドは、プログラムの実行中にバックグラウンドで補助サービスを提供するスレッドを指します。私たちがよく言うGCスレッド(ガベージコレクションスレッド)は、典型的なデーモンスレッドです。デーモンスレッドの特徴は、JVMがビジネススレッドがないことを検出すると、ビジネススレッドが終了し、それに応じてデーモンスレッドが終了することです。Javaでは、デーモンスレッドの実装も非常に簡単で、ThreadオブジェクトのsetDaemon(true)を直接呼び出すだけです。デーモンスレッドを使用するときは、次の3つの点に注意してください。
- thread.setDaemon()はthread.start()の前に呼び出す必要があります。そうしないと、IllegalThreadStateExceptionがスローされます。通常のスレッドをデーモンスレッドとして設定することはできません。
- デーモンスレッドから生成されたスレッドもデーモンスレッドです
- デーモンスレッドは、ファイルやデータベースなどの固有のリソースにアクセスしようとしないでください。彼は操作の途中で終了する可能性があるためです。
第二に、Javaスレッドのライフサイクル
Javaでは、私たちがよく言うライフサイクルは大きく次のように分けられます。
- 新しいスレッド
- スレッドレディランナブル
- 実行中のスレッド
- ブロックされたスレッドブロッキング(待機を待機しているスレッドもここでカウントできます。実際の違いがあります)
- スレッドデッド
特定のスレッドライフサイクルの切り替えは、次の図を参照できます。
3、Javaでスレッドを作成する方法
公式のjdkドキュメントでは、スレッドを作成する方法が2つあります。
- Threadクラスを継承します
public class TheadDemo extends Thread {
@Override
public void run() {
System.out.println("集成Thread类");
}
}
- 実行可能なインターフェースを実装する
public class ThreadDemo02 implements Runnable {
@Override
public void run() {
System.out.println("实现runnable接口");
}
}
4.面接の質問
1)スレッドがstart()を2回呼び出すことができないのはなぜですか?
Javaスレッドを2回開始することは許可されていません。2回目の呼び出しでは、実行時例外であるIllegalThreadStateExceptionが必然的にスローされます。startを複数回呼び出すと、プログラミングエラーと見なされます。
2)start()とrun()の違いは何ですか?
- start()メソッドを呼び出した後、jvmは新しい子スレッドを作成し、次にrun()メソッドを呼び出して子スレッドを開始します。(startメソッドは本当にマルチスレッド操作を実現し、runメソッド本体の実行を待たずに次のコードを実行できます);
- また、run()メソッドを直接呼び出すと、プログラムは引き続きメインスレッドを使用して実行します。プログラムにはスレッドと実行パスが1つしかないため、プログラムは順次実行する必要があり、待機する必要があります。
添付ファイル:簡単なテストコード
// 新建线程
public class TheadDemo extends Thread {
@Override
public void run() {
println("开始执行run方法体,此时时间为:"+new Date());
try {
Thread.currentThread().sleep(1000l*10);
String name = Thread.currentThread().getName();
System.err.println("当前线程:"+name+"执行结束");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static void println(String message) {
System.out.println(message);
}
}
public static void main(String[] args) throws InterruptedException {
TheadDemo theadDemo = new TheadDemo();
theadDemo.start();
System.err.println("主流程继续运行,此时时间为:"+new Date());
TheadDemo theadDemo2 = new TheadDemo();
theadDemo2.run();
System.err.println("主流程继续运行,此时时间为:"+new Date());
}