Ali p9は、Javaマルチスレッドの原理を3分で理解することを教えてくれます

はじめに
スレッドプールは、その名前が示すように、スレッドを格納するためのプールです。より学術的に言えば、スレッドリソースのコレクションです。なぜスレッドプールの概念があるのですか?前に考えてみてください。スレッドが必要な場合は、手動で直接作成し、タスクの実行後は気にしません。スレッドは、非同期タスクを実行するためのツールまたはキャリアです。料金はかかりません。スレッド自体に多くの注意を払う。ライフサイクルがシステムまたは環境に与える影響。マルチスレッドタスクの実行結果の出力にのみ焦点を当て、目標は達成されますが、保守と監視スレッドリソースの数は本当に無視されます。大規模システムで多数のマルチスレッドリソースを使用することで、マルチスレッドの注意、保守、管理の欠如がリソース占有への影響を徐々に拡大し、パフォーマンスを低下させ、人々の考えを喚起しました。

  1. リストアイテム

マルチスレッドの作成と破棄は、マルチスレッドのライフサイクルの大部分を占めます。この部分は、実際にはリソースとパフォーマンスを消費します。スレッドを使用して単純なタスクを実行する場合、スレッドの保守コストはタスクの利点を上回ります。実行。損失する価値がないため、スレッドプールが作成されます。スレッドプールを使用することで、スレッドのライフサイクルを制御でき、スレッドを簡単に取得して再利用でき、スレッドの頻繁な作成と破棄によって発生する追加のパフォーマンスオーバーヘッドを回避できます。これはおそらく、スレッドプールの導入。

1.マルチスレッド作成メソッド
1.1。Threadクラスを継承してスレッドクラスを作成します
1.実装手順
Threadクラスを継承するサブクラスを定義し、このクラスのrun()メソッドをオーバーライドします。

Threadサブクラスのインスタンスを作成します。つまり、スレッドオブジェクトを作成します。

スレッドオブジェクトのstart()メソッドを呼び出して、スレッドを開始します。

2.カーネル心代码
`classSomeThead extends Thraad {public void run(){//ここで何かを行う
}
}

public static void main(String [] args){SomeThread oneThread = new SomeThread();
//启PIN
ワイヤーoneThread.start(); } `

1.2。Runnableインターフェースを実装してスレッドクラスを作成する
1.実装手順
Runnableインターフェースの実装クラスを定義し、インターフェースのrun()メソッドを書き直します。

Runnable実装クラスのインスタンスを作成し、このインスタンスをThreadのターゲットオブジェクトとして使用します。つまり、Threadオブジェクトは実際のスレッドオブジェクトです。

2.カーネル心代码
クラスSomeRunnableはRunnableを実装します{publicvoid run(){//ここで何かを実行します}} Runnable oneRunnable = new SomeRunnable(); スレッドoneThread = new Thread(oneRunnable); oneThread.start();

1.3。CallableとFutureを使用してスレッドを作成する
1.実装手順
Callableインターフェイスの実装クラスを作成し、call()メソッドを実装します。変更されたメソッドはスレッド実行本体になり、戻り値があります。

Callable実装クラスのインスタンスを作成し、FutrueTaskクラスを使用してCallableオブジェクトをラップします。FutureTaskオブジェクトは、Callableオブジェクトのcall()メソッドの戻り値をカプセル化します。

FutureTaskオブジェクトをThreadオブジェクトのターゲットとして使用して、新しいスレッドを作成して開始します

FutureTaskオブジェクトのget()メソッドを呼び出して、子スレッドの実行が終了した後に戻り値を取得します。

2.コアコード
`//1。Callableインターフェイスの実装クラスを作成し、call()メソッドを実装します。publicclassSomeCallable01はCallableを実装します{@Overridepublic Integer call()throws Exception {int i = 0; for(; i < 10; i ++){System.out.println(Thread.currentThread()。getName()+ "" + i);} return i;}

public static void main(String [] args){ // 2.Callable実装クラスのインスタンスを作成しますSomeCallable01ctt = new SomeCallable01();

//3.使用FutrueTask类进行包装Callable对象,FutureTask对象封装了Callable对象的call()方法的返回值
FutureTask<Integer> ft = new FutureTask<>(ctt);

//开启ft线程
for(int i = 0;i < 21;i++)
{
    System.out.println(Thread.currentThread().getName()+" 的循环变量i的值"+i);
    if(i==20)//i为20的时候创建ft线程
    {
    	//4.使用FutureTask对象作为Thread对象的target创建并启动新线程
        new Thread(ft,"有返回值的线程FutureTask").start();
    }
}

//ft线程结束时,获取返回值
try
{	
	//5.调用FutureTask对象的get()方法获取子线程执行结束后的返回值。
    System.out.println("子线程的返回值:"+ft.get());//get()方法会阻塞,直到子线程执行结束才返回
} catch (InterruptedException e)
{
    e.printStackTrace();
} catch (ExecutionException e)
{
    e.printStackTrace();
}

}
コピーコード
} `

次に、スレッドの作成方法の違い
1.継承されたThreadクラスを使用して複数のスレッドを作成します
1)利点
記述簡単です。現在のスレッドにアクセスする必要がある場合は、Thread.currentThreadを使用する必要はありません。 ()メソッド。これを直接使用して、現在のスレッドを取得できます。

2)デメリット
スレッドクラスはThreadクラスを継承しているため、他の親クラスから継承できなくなります。(単一継承には制限があります)

複数のスレッドを作成する場合、各タスクには共有されないメンバー変数があり、共有を実現するには静的を追加する必要があります

2. Runnableクラスの実装方法を使用してマルチスレッドを作成します
。1)利点
単一継承の制限を回避します。複数のスレッドがターゲットオブジェクトを共有できるため、同じリソースを処理するマルチスレッドに非常に適しています。

2)欠点は
より複雑で、スレッドへのアクセスにはThread.currentThread()メソッドを使用する必要があり、戻り値はありません。

3. Callableインターフェースの実装方法を使用して、複数のスレッドを作成します
。1)利点
戻り値があり、単一継承の制限を回避し、複数のスレッドがターゲットオブジェクトを共有できるため、マルチスレッド処理に非常に適しています。同じリソース。

2)デメリットは
より複雑であり、スレッドにアクセスするにはThread.currentThread()メソッドを使用する必要があります

4. RunnableとCallableの違い
1)Callable stipulates(override)メソッドはcall()であり、Runnable stipulates(override)メソッドはrun()です。

2)呼び出し可能なタスクは実行後に値を返すことができますが、実行可能なタスクは値を返すことができません。

3)callメソッドは例外をスローできますが、runメソッドはスローできません。

4)Callableタスクを実行して、非同期計算の結果を表すFutureオブジェクトを取得します。計算が完了したかどうかを確認し、計算が完了するのを待ち、計算結果を取得する方法を提供します。Futureオブジェクトを使用すると、タスクの実行を理解し、タスクの実行をキャンセルして、実行結果future.get()を取得できます。

3.マルチスレッドスケジューリング
3.1。スケジューリング戦略
タイムスライス:スレッドスケジューリングはタイムスライスローテーションを採用します。プリエンプティブタイプ:優先度の高いスレッドがCPUをプリエンプトします。

3.2。Javaスケジューリング方法
1)同じ優先度のスレッドが先入れ先出しキュー(先着順)を形成する場合は、タイムスライス戦略を使用します

2)優先度が高い場合は、優先度スケジューリングのプリエンプティブ戦略を使用します

3.3、スレッドの優先度
レベル:

MAX_PRIORITY:10

MIN_PRIORITY:1

NORM_PRIORITY:5

方法:

`getPriority():スレッドの優先度を返します

setPriority(int newPriority):スレッドの優先度を変更します `

備考:

優先度の高いスレッドは、優先度の低いスレッドのCPU実行権をプリエンプトする必要があります。ただし、確率の観点からのみ、優先度の高いスレッドが実行される可能性が高くなります。優先度の低いスレッドが実行される前に、優先度の高いスレッドのみが実行されるという意味ではありません。

4.マルチスレッド状態管理
4.1。スレッドsleep-sleep1
)概要
現在実行中のスレッドを一定期間一時停止してブロッキング状態に入る必要がある場合は、Threadのsleepメソッドを呼び出すことができます。

2)スレッドスリープメソッド
実行中のスレッドを指定されたミリ秒数以内にスリープ状態にします。

sleep(long millis)指定されたミリ秒数と指定されたナノ秒数の範囲内で実行中のスレッドをスリープします。

睡眠(長いミリ、intナノ)

3)コード実装
sleepは静的メソッドであり、Threadのインスタンスオブジェクトで呼び出さないことをお勧めします。これは、それを呼び出すスレッドオブジェクトではなく、現在実行中のスレッドをスリープするためです。これはスレッドに対してのみ有効です。実行状態のオブジェクト。

`public class SynTest {public static void main(String [] args){new Thread(new CountDown()、“倒计時間”)。start(); }}

クラスCountDownはRunnable {int time = 10;を実装します。public void run(){while(true){if(time> = 0){System.out.println(Thread.currentThread()。getName()+“:” + time–); {Thread.sleep(1000);を試してください。//睡眠時間是1秒} catch(InterruptedException e){e.printStackTrace(); }}}}} `

4)備考
JavaスレッドスケジューリングはJavaマルチスレッドの中核であり、システムのパフォーマンスを十分に発揮し、プログラムの実行効率を向上させることができるのは、適切なスケジューリングだけです。ただし、プログラマーがスケジュールをどのように記述しても、スレッドの実行順序に最大の影響を与えるだけで、正確な制御を実現することはできません。スリープ方式を使用した後、スレッドはブロッキング状態になり、スリープ時間が経過した場合にのみ、スレッドは再び準備完了状態になり、準備完了状態はシステムによって制御される実行状態になります。正確に干渉することはできません。したがって、Thread.sleep(1000)を呼び出してスレッドを1秒間スリープさせると、結果は1秒より長くなる可能性があります。

4.2。スレッドの譲歩-yield1
)概要
yield()メソッドはsleep()メソッドに似ています。これは、Threadクラスによって提供される静的メソッドでもあります。また、現在実行中のスレッドを一時停止して、CPUリソースを他のユーザーに譲ることもできます。糸。ただし、sleep()メソッドとは異なり、ブロッキング状態にはならず、準備完了状態になります。yield()メソッドは、現在のスレッドを一時停止し、準備ができたスレッドプールに再入して、システムのスレッドスケジューラに再度スケジュールを設定させるだけです。この状況は、スレッドがyield()メソッドを呼び出すと、スレッドスケジューラである可能性があります。実行のために実行状態に入るために、それを再度スケジュールします。

実際、スレッドがyield()メソッドを呼び出してサスペンドする場合、優先度は現在のスレッドの優先度と同じであるか、現在のスレッドの準備完了状態よりも優先度が高いスレッドが実行される可能性が高くなります。もちろん、それは可能です。CPUスケジューリングスレッドに正確に干渉することは不可能だからです。

2)コード実装
public class Test1 { public static void main(String [] args)throws InterruptedException { new MyThread( "low level"、1).start(); new MyThread( "intermediate"、5).start(); new MyThread( "Advanced"、10).start(); } }





class MyThread extends Thread { public MyThread(String name、int pro){ super(name); //スレッドの名前を設定しますthis.setPriority(pro); //優先度を設定します}



@Override  
public void run() {  
    for (int i = 0; i < 30; i++) {  
        System.out.println(this.getName() + "线程第" + i + "次执行!");  
        if (i % 5 == 0)  
            Thread.yield();  
    }  
}  

}
コピーコード
3)スリープとyieldの
違い①sleepメソッドが現在のスレッドを一時停止した後、ブロッキング状態になります。スリープ時間が経過した場合にのみ、レディ状態になります。yieldメソッドが呼び出された後、直接ready状態になるため、ready状態に入り、実行状態にスケジュールされる場合があります。

②sleepメソッドステートメントはInterruptedExceptionをスローするため、sleepメソッドを呼び出すときは、例外をキャッチする必要があります。そうしないと、displayステートメントが例外をスローします。yieldメソッドは、タスク例外がスローされることを宣言していません。

③sleep方式はyield方式よりも移植性が高く、通常はyield方式に依存せずに並行スレッドの実行を制御します。

4.3。スレッドのマージ-結合
1)概要
スレッドのマージの意味は、複数の並列スレッドのスレッドを1つのスレッドにマージして実行することです。アプリケーションのシナリオは、スレッドが実行される前に別のスレッドが実行されるのを待つ必要がある場合です。スレッドクラスは、この関数を完了するためにjoinメソッドを使用します。静的メソッドではないことに注意してください。

要するに:

BスレッドがAスレッドの.join()メソッドを実行すると、Bスレッドは待機し、Aスレッドが終了するとBスレッドが実行されます。joinを使用して、実行のためにスレッドを一時的に結合できます。

2)スレッドマージメソッド
3つのオーバーロードされたメソッドがあります。

現在のスレッドは、スレッドがスレッドに参加するのを待ち、スレッドが終了するのを待ちます。

void join()

現在のスレッドがスレッドの終了を待機する最長時間はミリ秒です。

スレッドがミリ秒以内に実行されない場合、現在のスレッドは準備完了状態になり、CPUスケジューリングを再度待機します

ボイドジョイン(ロングミリ)

このスレッドが終了するまでの最長待機時間はミリ秒+ナノ秒です

ナノ秒。スレッドがミリ秒以内に実行されない場合、現在のスレッドは準備完了状態になり、CPUスケジューリングを再度待機します

ボイド結合(longミリ、int nanos)

3)コードの実装
public static void main(String [] args)throws InterruptedException { yieldDemo ms = new yieldDemo(); Thread t1 = new Thread(ms、 "Zhang San is left after eat "); Thread t2 = new Thread(ms 、 "Li Siは食べた後に去った");スレッドt3 = new Thread(ms、 "Wang Wuは食べた後に去った"); t1.start(); t1.join();





    t2.start();
    t3.start();
    System.out.println( "主线程");
}`

スレッドt = new Thread(()-> { try { Thread.sleep(1000); } catch(InterruptedException e){ e.printStackTrace(); } r = 10; });






t.start();
//メインスレッドをブロックし、tスレッドが実行されるのを待ってから続行します
//行を削除すると、実行結果は0になり、行の実行結果は10になります
t.join();
log.info( "r:{}"、r);

//実行結果
13:09:13.892 [main] INFO thread.TestJoin-r:10
コピーコード
4.4、スレッド優先度の設定
1)概要
各スレッドは実行時に優先度属性を持ち、優先度の高いスレッドはより多くの実行を取得できます一方、優先度の低いスレッドは実行の機会が少なくなります。スレッドスリープと同様に、スレッドの優先順位はスレッドの実行順序を保証できません。ただし、優先度の高いスレッドはCPUリソースを取得する可能性が高く、優先度の低いスレッドには実行の機会がないわけではありません。

各スレッドのデフォルトの優先度は、それを作成した親スレッドと同じ優先度です。デフォルトでは、メインスレッドの優先度は通常です。

2)優先度メソッドの関与
Threadクラスは、指定されたスレッドの優先度を設定および返すためのsetPriority(int newPriority)メソッドとgetPriority()メソッドを提供します。setPriorityメソッドのパラメーターは、1〜0の範囲の整数です。 Threadクラスによって提供される3つの静的定数:

MAX_PRIORITY = 10 MIN_PRIORITY = 1 NORM_PRIORITY = 5

3)コード実装
public class Test1 { public static void main(String [] args)throws InterruptedException { new MyThread( "high level"、10).start(); new MyThread( "low level"、1).start() ; } }




class MyThread extends Thread {  
    public MyThread(String name,int pro) {  
        super(name);//设置线程的名称  
        setPriority(pro);//设置线程的优先级  
    }  
    @Override  
    public void run() {  
        for (int i = 0; i < 100; i++) {  
            System.out.println(this.getName() + "线程第" + i + "次执行!");  
        }  
    }  
}

コピーコード
4)備考
Javaには10の優先度レベルがありますが、これらの優先度レベルにはオペレーティングシステムのサポートが必要です。異なるオペレーティングシステムの優先度は同じではなく、Javaの10の優先度レベルにうまく対応していません。したがって、MAX_PRIORITY、MIN_PRIORITY、およびNORM_PRIORITYの3つの静的定数を使用して優先順位を設定し、プログラムの最高の移植性を確保する必要があります。

4.5。バックグラウンド(デーモン)スレッド
1)概要
デーモンスレッド使用はまれですが、役に立たないわけではありません。たとえば、JVMのガベージコレクションやメモリ管理などのスレッドはすべてデーモンスレッドです。データベースアプリケーションを実行するときに使用されるデータベース接続プールもあります。接続プール自体には、接続数、タイムアウト期間、ステータスなどを監視するための多くのバックグラウンドスレッドも含まれています。

デフォルトでは、Javaプロセスは、すべてのスレッドが終了するのを待ってから終了する必要があります。デーモンスレッドと呼ばれる特別なスレッドがあります。デーモン以外のすべてのスレッドが終了すると、終了していなくても、強制的に終了します。 。

2)メソッドの関与
スレッドオブジェクトのメソッドsetDaemon(true)を呼び出して、デーモンスレッドとして設定します。

スレッドをデーモンスレッドまたはユーザースレッドとしてマークします。実行中のスレッドがすべてデーモンスレッドの場合、Java仮想マシンは終了します。このメソッドは、スレッドを開始する前に呼び出す必要があります。このメソッドは、最初にパラメーターなしでスレッドのcheckAccessメソッドを呼び出します。これにより、(現在のスレッドで)SecurityExceptionがスローされる場合があります。

public final void setDaemon(boolean on)
パラメーター:on-trueの場合、スレッドをデーモンスレッドとしてマークします。スロー

IllegalThreadStateException-スレッドがアクティブな場合。
SecurityException-現在のスレッドがスレッドを変更できない場合。

3)
デーモンスレッドの目的デーモンスレッドは通常、アプリケーションの実行中にバックグラウンドミュージックを再生したり、テキストエディタで自動文法チェックや自動保存を実行したりするなど、いくつかのバックグラウンドタスクを実行するために使用されます。

Javaのガベージコレクションもデーモンスレッドです。ガードラインの利点は、その終わりを気にする必要がないことです。たとえば、アプリケーションの実行中にバックグラウンドミュージックを再生したい場合、バックグラウンドミュージックを再生するスレッドをデーモン以外のスレッドに設定すると、ユーザーが終了を要求したときに、メインスレッドを終了するだけでなく、通知する必要があります。再生するBGMスレッドは終了します。デーモンスレッドとして設定されている場合は、必要ありません。

4.6。スレッドを停止する
1)概要
Thread.stop()、Thread.suspend、Thread.resume、Runtime.runFinalizersOnExitスレッドの実行を終了するこれらのメソッドは廃止されており、使用することは非常に安全ではありません。

スレッドを停止する正しい方法:

最初:runメソッドは正常に実行され、その後終了します。

2番目:ループ条件と判断条件の識別子を制御して、スレッドを終了します。

2)実装例
クラスMyThread extends Thread {int i = 0; boolean next = true; @Override public void run(){while(next){if(i == 10)next = false; i ++; System.out.println(i); }}}

4.7。スレッドの割り込み—割り込み
1)割り込み(割り込み)とは何ですか?
割り込みは単なる協調メカニズムです。Javaは割り込みに構文を追加しません。割り込みプロセスはプログラマー自身が完全に実装する必要があります。

各スレッドオブジェクトには、スレッドが中断されているかどうかを示すために使用されるフラグがあります。フラグビットは中断を示すためにtrueであり、中断されていないことを示すためにfalseです。

スレッドオブジェクトの割り込みメソッドを呼び出して、スレッドのフラグをtrueに設定します。他のスレッドまたは独自のスレッドで呼び出すことができます。

中断フラグ:スレッドが中断されているかどうか、trueは中断されていることを意味し、falseは中断されていないことを意味します

2)メソッド
isInterrupted()メソッドを含む:

スレッドの中断マークを取得します(どのスレッドオブジェクトが呼び出されているかを確認します)。呼び出し後にスレッドの中断マークは変更されません。

Interrupt()メソッド:

このスレッドを中断します(誰を中断するためにどのスレッドオブジェクトが呼び出されますか)。割り込みが必要なスレッドがブロック状態(スリープ、待機、参加)の場合、その割り込み状態はクリアされ、例外(InterruptedException)がスローされます。この中断は実際にはスレッドを停止していませんが、中断状態を「停止」状態に設定すると、スレッドは実行を継続します。スレッドを停止する方法については、自分で停止する必要があります。この方法は停止するだけです。スレッドの状態は「停止」状態に設定されます。これはtrueです。

通常のスレッドを中断します。スレッドは中断されませんが、スレッドの中断はtrueとしてマークされます。

Interrupted()メソッド:

現在のスレッドが中断されているかどうかを確認し、上記のinterrupt()メソッドと組み合わせて使用​​します。スレッドの中断ステータスは、このメソッドによってクリアされます。つまり、このメソッドが2回連続して正常に呼び出された場合、2回目はクリアされます。

呼び出しはfalseを返します(最初の呼び出しの後、2番目の呼び出しの前に現在のスレッドが再び中断されない限り)。

言い換えると、呼び出し後に割り込みフラグをクリアします。つまり、trueになった場合、呼び出し後の割り込みフラグはfalseです(一般的には使用されません)。

4.8。スレッドのブロック
スレッドのブロックは多くのタイプに分けることができます。オペレーティングシステムレベルとJavaレベルでのブロックの定義は異なる場合がありますが、広い意味で、スレッドをブロックする方法はいくつかあります。

1)BIOブロッキング、つまり、ブロッキングioストリームが使用されます

2)スリープ(長時間)スレッドをブロッキング状態でスリープ状態にします

3)a.join()このメソッドを呼び出すスレッドはブロッキングに入り、スレッドの実行が終了して実行を再開するのを待ちます

4)sychronizedまたはReentrantLockにより、スレッドはロックを取得せずにブロック状態になります

5)ロックを取得した後にwait()メソッドを呼び出すと、スレッドもブロッキング状態になります

6)LockSupport.park()により、スレッドはブロッキング状態に入ることができます

V.スレッドコアメソッドの概要5.1。6
つのスレッド状態とメソッド間の対応

ここに画像の説明を挿入します

5.2。スレッドコアメソッドの概要
1)Threadクラスのコアメソッド
2)オブジェクトのスレッド関連メソッド
ここに画像の説明を挿入します

総括する
ここに画像の説明を挿入します

最近多くの人がインタビューを行っています。ここに複数のコピーをまとめました:Javaマルチスレッド資料、Springファミリーバケット(1187ページのドキュメント)、Javaシステム化資料:( 2021年の最新のJavaコアナレッジポイント、Javaインタビュートピックおよびインターネットの実際の質問を含む) 、電子書籍など21年でまとめたもの)、困っている友達はQQグループ「748945508」に参加して無料で入手できます。

おすすめ

転載: blog.csdn.net/dcj19980805/article/details/114693244