検索
ホームページJava&#&チュートリアルJava Threadマルチスレッドの包括的な分析

マルチスレッドは Java の非常に重要な知識ポイントです。ここでは、エディターが Java スレッドのマルチスレッドについてまとめますので、ぜひマスターしてください。

1. スレッドのライフ サイクルと 5 つの基本的な状態

Java のスレッドのライフ サイクルに関しては、まず下のより古典的な図を見てください:

Java Thread多线程全面解析

上の図は基本的に Java の多くの側面をカバーしています。糸のポイント。上図の各知識ポイントをマスターすれば、基本的に Java でのマルチスレッドをマスターできます。主に以下が含まれます:

Java スレッドには 5 つの基本的な状態があります

新しい状態 (New): スレッド オブジェクトのペアが作成されると、次のような新しい状態になります。 Thread t = new MyThread();状態 (Runnable): スレッド オブジェクトの start() メソッド (t.start();) が呼び出されると、スレッドは準備完了状態になります。準備完了状態のスレッドは、スレッドが準備ができており、いつでも CPU スケジューリングの実行を待機していることを意味します。 : CPU が準備完了状態のスレッドのスケジュールを開始すると、この時点でスレッドは実際に実行可能になります。つまり、実行状態になります。注: 準備完了状態は、実行状態への唯一の入り口です。つまり、スレッドが実行のために実行状態に入りたい場合は、まず準備完了状態 (ブロック) でなければなりません。何らかの理由で実行状態にあるスレッドは、CPU の使用権を一時的に放棄し、実行を停止するため、準備完了状態になるまでブロック状態になる可能性があります。実行状態になるために CPU によって再度呼び出されます。

ブロックのさまざまな理由に応じて、ブロック状態は 3 つのタイプに分類できます。


1. ブロック待機中: 実行状態のスレッドは wait() メソッドを実行して待機ブロック状態に入ります


2 .同期ブロッキング -- スレッドが同期ロックの取得に失敗した場合 (ロックが他のスレッドによって占有されているため)、スレッドは同期ブロッキング状態に入ります。

3. スレッドのスリープを呼び出すことにより、同期ブロッキング状態になります。 () または join() または I/O リクエストが発行されると、スレッドはブロッキング状態になります。 sleep() 状態がタイムアウトになるか、join() がスレッドの終了を待つかタイムアウトになるか、I/O 処理が完了すると、スレッドは再び準備完了状態に入ります。

デッド状態 (Dead): スレッドは実行を終了したか、例外により run() メソッドを終了し、スレッドはライフサイクルを終了します。

2. Java マルチスレッドの作成と起動

Java でのスレッドの作成は 3 つの基本的な形式に共通しています

1. Thread クラスを継承し、このクラスの run() メソッドをオーバーライドします。

class MyThread extends Thread {
private int i = ;
@Override
public void run() {
for (i = ; i < ; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
}
} 
public class ThreadTest {
public static void main(String[] args) {
for (int i = ; i < ; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
if (i == ) {
Thread myThread = new MyThread(); // 创建一个新的线程 myThread 此线程进入新建状态
Thread myThread = new MyThread(); // 创建一个新的线程 myThread 此线程进入新建状态
myThread.start(); // 调用start()方法使得线程进入就绪状态
myThread.start(); // 调用start()方法使得线程进入就绪状态
}
}
}
}

上に示したように、run() メソッドをオーバーライドして、Thread クラスを継承し、新しいスレッド クラス MyThread を定義します。 run() メソッドのメソッド本体は、スレッドと呼ばれる、スレッドが完了する必要があるタスクを表します。実行本体。このスレッド クラス オブジェクトが作成されると、新しいスレッドが作成され、スレッド新規状態になります。スレッドオブジェクトが参照するstart()メソッドを呼び出すことで、スレッドは実行可能状態になります。このとき、CPUのスケジューリングタイミングによっては、すぐにスレッドが実行されない場合があります。


2. Runnable インターフェースを実装し、インターフェースの run() メソッドを書き換えます。 run() メソッドは、Runnable 実装クラスのインスタンスを作成し、このインスタンスを Thread のターゲットとして使用します。クラスを使用して Thread オブジェクトを作成すると、Thread オブジェクトが実際のスレッド オブジェクトになります。

class MyRunnable implements Runnable {
private int i = ;
@Override
public void run() {
for (i = ; i < ; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
}
} 
public class ThreadTest {
public static void main(String[] args) {
for (int i = ; i < ; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
if (i == ) {
Runnable myRunnable = new MyRunnable(); // 创建一个Runnable实现类的对象
Thread thread = new Thread(myRunnable); // 将myRunnable作为Thread target创建新的线程
Thread thread = new Thread(myRunnable);
thread.start(); // 调用start()方法使得线程进入就绪状态
thread.start();
}
}
}
}

新しいスレッドを作成する上記の 2 つの方法は誰もがよく知っていると思いますが、Thread と Runnable の関係は何でしょうか?まずは次の例を見てみましょう。

public class ThreadTest {
public static void main(String[] args) {
for (int i = ; i < ; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
if (i == ) {
Runnable myRunnable = new MyRunnable();
Thread thread = new MyThread(myRunnable);
thread.start();
}
}
}
}
class MyRunnable implements Runnable {
private int i = ;
@Override
public void run() {
System.out.println("in MyRunnable run");
for (i = ; i < ; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
}
}
class MyThread extends Thread {
private int i = ;
public MyThread(Runnable runnable){
super(runnable);
}
@Override
public void run() {
System.out.println("in MyThread run");
for (i = ; i < ; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
}
}

同様に、Runnableインターフェースを実装してスレッドを作成する方法と似ていますが、違いは

Thread thread = new MyThread(myRunnable);

ということで、この方法でスムーズに新しいスレッドを作成できるでしょうか?答えは「はい」です。この時のスレッドの実行本体は、MyRunnableインターフェースのrun()メソッドなのか、MyThreadクラスのrun()メソッドなのか。出力から、スレッドの実行本体が MyThread クラスの run() メソッドであることがわかります。実際、その理由は非常に単純です。Thread クラス自体も Runnable インターフェイスを実装しており、run() メソッドは最初に Runnable インターフェイスで定義されているからです。

public interface Runnable {
public abstract void run();
}

Thread クラスの Runnable インターフェイスの run() メソッドの実装を見てみましょう:

  @Override
public void run() {
if (target != null) {
target.run();
}
}

つまり、Thread クラスの run() メソッドが実行されると、最初に次のことが決定されます。ターゲットが存在するかどうか、存在する場合は実行します。 ターゲットの run() メソッドは、Runnable インターフェイスを実装し、 run() メソッドをオーバーライドするクラスの run() メソッドです。ただし、上記の例では、ポリモーフィズムの存在により、Thread クラスの run() メソッドはまったく実行されませんが、ランタイム型、つまり MyThread クラスの run() メソッドは直接実行されます。最初に実行されました。

3. Callable インターフェイスと Future インターフェイスを使用してスレッドを作成します。具体的には、Callableインターフェースの実装クラスを作成し、clam()メソッドを実装します。そして、FutureTask クラスを使用して Callable 実装クラスのオブジェクトをラップし、この FutureTask オブジェクトを Thread オブジェクトのターゲットとして使用してスレッドを作成します。

少し複雑に思えますが、例を見れば明らかになるでしょう。

public class ThreadTest {
public static void main(String[] args) {
Callable<Integer> myCallable = new MyCallable(); // 创建MyCallable对象
FutureTask<Integer> ft = new FutureTask<Integer>(myCallable); //使用FutureTask来包装MyCallable对象
for (int i = ; i < ; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
if (i == ) {
Thread thread = new Thread(ft); //FutureTask对象作为Thread对象的target创建新的线程
thread.start(); //线程进入到就绪状态
}
}
System.out.println("主线程for循环执行完毕..");
try {
int sum = ft.get(); //取得新创建的新线程中的call()方法返回的结果
System.out.println("sum = " + sum);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
class MyCallable implements Callable<Integer> {
private int i = ;
// 与run()方法不同的是,call()方法具有返回值
@Override
public Integer call() {
int sum = ;
for (; i < ; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
sum += i;
}
return sum;
}
}

首先,我们发现,在实现Callable接口中,此时不再是run()方法了,而是call()方法,此call()方法作为线程执行体,同时还具有返回值!在创建新的线程时,是通过FutureTask来包装MyCallable对象,同时作为了Thread对象的target。那么看下FutureTask类的定义:

public class FutureTask<V> implements RunnableFuture<V> {
//....
} 
public interface RunnableFuture<V> extends Runnable, Future<V> {
void run();
}

于是,我们发现FutureTask类实际上是同时实现了Runnable和Future接口,由此才使得其具有Future和Runnable双重特性。通过Runnable特性,可以作为Thread对象的target,而Future特性,使得其可以取得新创建线程中的call()方法的返回值。

执行下此程序,我们发现sum = 4950永远都是最后输出的。而“主线程for循环执行完毕..”则很可能是在子线程循环中间输出。由CPU的线程调度机制,我们知道,“主线程for循环执行完毕..”的输出时机是没有任何问题的,那么为什么sum =4950会永远最后输出呢?

原因在于通过ft.get()方法获取子线程call()方法的返回值时,当子线程此方法还未执行完毕,ft.get()方法会一直阻塞,直到call()方法执行完毕才能取到返回值。

上述主要讲解了三种常见的线程创建方式,对于线程的启动而言,都是调用线程对象的start()方法,需要特别注意的是:不能对同一线程对象两次调用start()方法。

三. Java多线程的就绪、运行和死亡状态

就绪状态转换为运行状态:当此线程得到处理器资源;

运行状态转换为就绪状态:当此线程主动调用yield()方法或在运行过程中失去处理器资源。

运行状态转换为死亡状态:当此线程线程执行体执行完毕或发生了异常。

此处需要特别注意的是:当调用线程的yield()方法时,线程从运行状态转换为就绪状态,但接下来CPU调度就绪状态中的哪个线程具有一定的随机性,因此,可能会出现A线程调用了yield()方法后,接下来CPU仍然调度了A线程的情况。

由于实际的业务需要,常常会遇到需要在特定时机终止某一线程的运行,使其进入到死亡状态。目前最通用的做法是设置一boolean型的变量,当条件满足时,使线程执行体快速执行完毕。如:

public class ThreadTest {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
for (int i = ; i < ; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
if (i == ) {
thread.start();
}
if(i == ){
myRunnable.stopThread();
}
}
}
}
class MyRunnable implements Runnable {
private boolean stop;
@Override
public void run() {
for (int i = ; i < && !stop; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
}
public void stopThread() {
this.stop = true;
}
}

以上所述是小编给大家介绍的Java Thread多线程全面解析,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对PHP中文网的支持!

更多Java Thread多线程全面解析相关文章请关注PHP中文网!


声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
Java開発のどの側面がプラットフォームに依存していますか?Java開発のどの側面がプラットフォームに依存していますか?Apr 26, 2025 am 12:19 AM

javadevelopmentisnotentirelylylypratform-IndopentDuetoseveralfactors.1)jvmvariationsaffectperformanceandbehavioracrossdifferentos.2)nativeLibrariesviajniintroducePlatform-specificissues.3)giaiasystemsdifferbeTioneplateplatifflics.4)

さまざまなプラットフォームでJavaコードを実行するときにパフォーマンスの違いはありますか?なぜ?さまざまなプラットフォームでJavaコードを実行するときにパフォーマンスの違いはありますか?なぜ?Apr 26, 2025 am 12:15 AM

Javaコードは、さまざまなプラットフォームで実行するときにパフォーマンスの違いがあります。 1)JVMの実装と最適化戦略は、OracleJDKやOpenJDKなどとは異なります。 2)メモリ管理やスレッドスケジューリングなどのオペレーティングシステムの特性もパフォーマンスに影響します。 3)適切なJVMを選択し、JVMパラメーターとコード最適化を調整することにより、パフォーマンスを改善できます。

Javaのプラットフォームの独立性の制限は何ですか?Javaのプラットフォームの独立性の制限は何ですか?Apr 26, 2025 am 12:10 AM

java'splatformindepentedencehaslimitationsincludingporformanceoverhead、versioncompatibulisisues、changleSwithnativeLibraryIntegration、プラットフォーム固有の機能、およびjvminStallation/maintenation。

プラットフォームの独立性とクロスプラットフォーム開発の違いを説明します。プラットフォームの独立性とクロスプラットフォーム開発の違いを説明します。Apr 26, 2025 am 12:08 AM

PlatformEndependEncealLowsProgramStorunonAnyPlatformWithOdification、whilecross-platformdevelopmentReadreessomeplatform-specificAdjustments.platformindependence、explifiedByjava、unableSiversAlexecutionButMayCompromperformance

ジャストインタイム(JIT)コンピレーションは、Javaのパフォーマンスとプラットフォームの独立性にどのような影響を与えますか?ジャストインタイム(JIT)コンピレーションは、Javaのパフォーマンスとプラットフォームの独立性にどのような影響を与えますか?Apr 26, 2025 am 12:02 AM

jitcompalilationinjavaenhancesperformance whelemaintaining formindepence.1)itdynamicallyTrantesiNTODENATIVEMACHINECODEATRUNTIME、最適化されたコードを最適化すること、

Javaがクロスプラットフォームデスクトップアプリケーションを開発するための人気のある選択肢なのはなぜですか?Javaがクロスプラットフォームデスクトップアプリケーションを開発するための人気のある選択肢なのはなぜですか?Apr 25, 2025 am 12:23 AM

javaispopularforsoss-platformdesktopapplicationsduetoits "writeonce、runaynay" philosophy.1)itusesbytecodatiTatrunnanyjvm-adipplatform.2)ライブラリリケンディンガンドジャヴァフククレアティック - ルルクリス

Javaでプラットフォーム固有のコードを作成する必要がある場合がある状況について話し合います。Javaでプラットフォーム固有のコードを作成する必要がある場合がある状況について話し合います。Apr 25, 2025 am 12:22 AM

Javaでプラットフォーム固有のコードを作成する理由には、特定のオペレーティングシステム機能へのアクセス、特定のハードウェアとの対話、パフォーマンスの最適化が含まれます。 1)JNAまたはJNIを使​​用して、Windowsレジストリにアクセスします。 2)JNIを介してLinux固有のハードウェアドライバーと対話します。 3)金属を使用して、JNIを介してMacOSのゲームパフォーマンスを最適化します。それにもかかわらず、プラットフォーム固有のコードを書くことは、コードの移植性に影響を与え、複雑さを高め、パフォーマンスのオーバーヘッドとセキュリティのリスクをもたらす可能性があります。

プラットフォームの独立性に関連するJava開発の将来の傾向は何ですか?プラットフォームの独立性に関連するJava開発の将来の傾向は何ですか?Apr 25, 2025 am 12:12 AM

Javaは、クラウドネイティブアプリケーション、マルチプラットフォームの展開、および言語間の相互運用性を通じて、プラットフォームの独立性をさらに強化します。 1)クラウドネイティブアプリケーションは、GraalvmとQuarkusを使用してスタートアップ速度を向上させます。 2)Javaは、埋め込みデバイス、モバイルデバイス、量子コンピューターに拡張されます。 3)Graalvmを通じて、JavaはPythonやJavaScriptなどの言語とシームレスに統合して、言語間の相互運用性を高めます。

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

PhpStorm Mac バージョン

PhpStorm Mac バージョン

最新(2018.2.1)のプロフェッショナル向けPHP統合開発ツール

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

Eclipse を SAP NetWeaver アプリケーション サーバーと統合します。

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

このプロジェクトは osdn.net/projects/mingw に移行中です。引き続きそこでフォローしていただけます。 MinGW: GNU Compiler Collection (GCC) のネイティブ Windows ポートであり、ネイティブ Windows アプリケーションを構築するための自由に配布可能なインポート ライブラリとヘッダー ファイルであり、C99 機能をサポートする MSVC ランタイムの拡張機能が含まれています。すべての MinGW ソフトウェアは 64 ビット Windows プラットフォームで実行できます。

VSCode Windows 64 ビットのダウンロード

VSCode Windows 64 ビットのダウンロード

Microsoft によって発売された無料で強力な IDE エディター