Javaマルチスレッドの基本的なスキル

1.プロセスとは何ですか?スレッドとは

exeプログラムと比較すると、プロセスは動的な概念であり、実行中のプログラムと言えます。プロセスは、リソース(CPU、メモリなど)の割り当ての基本単位です。
スレッドは、プロセス内で独立して実行されるサブタスクとして理解できます。これは、プログラムが実行されるときの最小単位です。
たとえばqq.exeプログラムが実行されているとき、友達の追加、ビデオ、ファイルのダウンロード、音楽の再生など、多くのサブタスクも同時に実行されます。
プロセスFuzhouは、オペレーティングシステムがリソースを申請することを望んでいます。プロセスでは、複数のスレッドがプロセス内の同じメモリまたはファイルリソースを共有できます

jvmの観点から分析ここに画像の説明を挿入
できます。プロセスには複数のスレッドが存在する可能性があり、複数のスレッドがプロセスのヒープとメソッド領域(JDK1.8以降のメタスペース)リソースを共有しますが、各スレッドには独自のプログラムカウンターがあります。 、仮想マシンスタックおよびローカルメソッドスタック。

2.マルチスレッドの利点

マルチスレッドの使用は、非同期の使用であり、同時に複数のタスクを実行できます

3.マルチスレッドを使用する場合

1)ブロックされました。システムにブロッキング現象が発生すると、マルチスレッド技術を使用して、実際の状況に応じて運用効率を向上させることができます
ビジネスは、AとBの2つの実行プロセスに分けられます。Aサービスがブロックされている場合、Bサービスの実行はAサービスの実行結果に依存しません。

4.スレッドの作成方法

スレッドの作成方法を学ぶ前に、スレッドクラスの宣言構造を見てください。

public class Thread implements Runable

継承時のJavaの特性により、----は多重継承をサポートしていないため、クラスをより適切に拡張するために、通常は実行可能なインターフェイスを実装するために使用します。つまり、実装中に継承します。ただし、2つの方法でスレッドを作成する機能は同じであり、本質的な違いはありません。

スレッドを作成する方法:
1。継承方法

new Thread(()->{
    
    },"").start();

2.実現する実行可能インターフェース

public class MyThread2 implements Runnable {
    
    //实现Runnable接口
  public void run(){
    
    
  //重写run方法
  }
}
public class Main {
    
    
  public static void main(String[] args){
    
    
    //创建并启动线程

    MyThread2 myThread=new MyThread2();

    Thread thread=new Thread(myThread);

    thread().start();

    //或者    new Thread(new MyThread2()).start();

  }

}

拡張:strat()メソッドは次の手順を実行します。

1.オペレーティングシステムにjvmを介してスレッドを作成するように指示します
。2。オペレーティングシステムはメモリを開き、Windows SDKのcreateThread()関数を使用してスレッドスレッドオブジェクトを作成します。
3.オペレーティングシステムは、実行のタイミングを決定するためにThreadオブジェクトをスケジュールします。4。スレッド
はオペレーティングシステムで正常に実行されます。

3.使用するスレッドプール

4.実現する呼び出し可能インターフェイス、rewrite == call()==メソッド、次にjava.util.concurrent.FutureTaskにラップし、次にThread
Callableにラップします。戻り値を持つスレッドはスレッドをキャンセルし、スレッドがキャンセルされたかどうかを判断できます。実行

public class Main {
    
    
    public static void main(String[] args) throws Exception {
    
    
    	 // 将Callable包装成FutureTask,FutureTask也是一种Runnable
        MyCallable callable = new MyCallable();
        //包装线程执行目标,因为Thread的构造函数只能接受Runnable接口的实现类,而FutureTask类实现了Runnable接口
        FutureTask<Integer> futureTask = new FutureTask<>(callable);
        //传入线程执行目标,实例化线程对象
        new Thread(futureTask).start();

        // get方法会阻塞调用的线程
        Integer sum = futureTask.get();
        System.out.println(Thread.currentThread().getName() + Thread.currentThread().getId() + "=" + sum);
    }
}


class MyCallable implements Callable<Integer> {
    
    

    @Override
    public Integer call() throws Exception {
    
    
        System.out.println(Thread.currentThread().getName() + "\t" + Thread.currentThread().getId() + "\t" + new Date() + " \tstarting...");
//具体重写call方法
        Thread.sleep(5000);

        System.out.println(Thread.currentThread().getName() + "\t" + Thread.currentThread().getId() + "\t" + new Date() + " \tover...");
        return sum;
    }
}

Callableは機能的なインターフェースでもあります

@FunctionalInterface
public interface Callable<V> {
    
    
    V call() throws Exception;
}

FutureTask

public class FutureTask<V> implements RunnableFuture<V> {
    
    
	// 构造函数
	public FutureTask(Callable<V> callable);
	
	// 取消线程
	public boolean cancel(boolean mayInterruptIfRunning);
	// 判断线程
	public boolean isDone();
	// 获取线程执行结果
	public V get() throws InterruptedException, ExecutionException;
}

RunnableFuture

public interface RunnableFuture<V> extends Runnable, Future<V> {
    
    
    void run();
}

上記のクラス間の関係:ここに画像の説明を挿入

3つの方法の比較:

  • スレッド:継承メソッド。Javaは単一継承であるため、お勧めしません。スレッドを継承した後は、他のクラスを継承する方法がないため、柔軟性が十分ではありません。
  • 実行可能:単一継承の制限なしで、Threadクラスよりも柔軟なインターフェースの実装
  • Callable:ThreadとRunnableはどちらもオーバーライドされたrun()メソッドであり、戻り値はありません。Callableはオーバーライドされたcall()メソッドであり、戻り値があり、FutureTaskクラスを使用して、スレッドが実行されたかどうかを判断したり、スレッドの実行をキャンセルしたりできます。
  • Runnableは、スレッドが戻り値を必要としない場合に使用され、Callableは、戻り値が必要な場合に使用されます。通常の状況では、スレッド本体コードはThreadクラスに直接配置されず、スレッドは通常、スレッドを介して開始されます。クラス
  • ThreadクラスはRunnableを実装し、CallableはFutureTaskにカプセル化され、FutureTaskはRunnableFutureを実装し、RunnableFutureはRunnableを継承するため、Callableも一種のRunnableであるため、3つの実装メソッドは本質的にRunnable実装です。

5.スレッドのスケジューリングはランダムです

6.スレッドのライフサイクル

	/**
     * 线程生命周期中的的六种状态
     * NEW:还没有调用start()的线程实例所处的状态
     * RUNNABLE:正在虚拟机中执行的线程所处的状态
     * BLOCKED:等待在监视器锁上的线程所处的状态
     * WAITING:等待其它线程执行特定操作的线程所处的状态
     * TIMED_WAITING:等待其它线程执行超时操作的线程所处的状态
     * TERMINATED:退出的线程所处的状态
     * 给定时间点,一个线程只会处于以下状态中的一个,这些状态仅仅是虚拟机层面的线程状态,并不能反映任何操作系统中线程的状态
     */
    public enum State {
    
    
        //还没有调用start()开启的线程实例所处的状态
        NEW, 
        //正在虚拟机中执行或者等待被执行的线程所处的状态,但是这种状态也包含线程正在等待处理器资源这种情况
        RUNNABLE,
        // 等待在监视器锁上的线程所处的状态,比如进入synchronized同步代码块或同步方法失败
        BLOCKED,
        // 等待其它线程执行特定操作的线程所处的状态;比如线程执行了以下方法: Object.wait with no timeout、Thread.join with no timeout、 LockSupport.park
        WAITING,
       // 等待其它线程执行超时操作的线程所处的状态;比如线程执行了以下方法: Thread.sleep、Object.wait with timeout
       //Thread.join with timeout、LockSupport.parkNanos、LockSupport.parkUntil
        TIMED_WAITING,
        //退出的线程所处的状态
        TERMINATED;
    }

ここに画像の説明を挿入
ステータスの詳細な説明:
1。初期状態(NEW)
スレッドクラスは、Runnableインターフェースを実装し、Threadから継承することで取得できます。newのインスタンスが出ると、スレッドは初期状態になります。
2.2。実行可能 start()メソッドを呼び出した後、スレッドはこの状態になります。この状態には、次の3つの状況が含まれます。

  1. 準備完了状態:CPUがタイムスライスを割り当てるのを待機しています[1.準備完了状態は、実行する資格があることを意味し、スケジューラーはあなたをピックアップしません。常に準備完了状態になります。2.スレッドのstart()メソッドが呼び出され、スレッドは準備完了状態になります。
  2. 実行状態:Runnableメソッドを入力してタスクを実行します
  3. ブロッキング状態:BIOがブロッキングIOストリームを実行するときの状態

3.3。ブロックされた
ロックが取得されていないときのブロック状態(ブロック状態とは、同期キーワードで変更されたメソッドまたはコードブロックに入るときにスレッドがブロックされる状態(ロックを取得する))
4。待っています(待っています)
wait()、join()、またはLockSupport.parkとThread.sleep()を呼び出した後の状態。この状態のスレッドにはCPU実行時間が割り当てられません。明示的にウェイクアップされるまで待機する必要があります。そうしないと、無期限に待機します。
5.5。タイムアウト待機(TIMED_WAITING)
sleep(time)、wait(time)、join(time)などのメソッドを呼び出した後の状態。この状態のスレッドにはCPU実行時間が割り当てられませんが、他のスレッドによってウェイクアップされるのを無期限に待つ必要はありません。一定時間後に自動的にウェイクアップします。
6.6。終了ステータス(TERMINATED)
スレッドが実行を終了した後、または例外をスローした後の状態。
次に例を示します。1。スレッドのrun()メソッドが完了するか、メインスレッドのmain()メソッドが完了すると、終了したと見なされます。このスレッドオブジェクトは生きている可能性がありますが、別の実行スレッドではなくなりました。スレッドが終了すると、生まれ変わることはできません。2.終了したスレッドでstart()メソッドを呼び出すと、java.lang.IllegalThreadStateExceptionがスローされます。

7.スレッドの優先順位

クラスでは、次の属性を使用して優先度を表します。

private int priority;

== setPriority(int newPriority)==で新しい優先度を設定し、getPriority()でスレッドの優先度を取得できます。
スレッドは優先度のソースコードを初期化します

Thread parent = currentThread();
this.priority = parent.getPriority();

スレッドのデフォルトの優先度は、親スレッドの優先度を継承することであることがわかりました。
厳密に言えば、子スレッドのデフォルトの優先度は親スレッドのデフォルトの優先度と同じであり、Javaメインスレッドのデフォルトの優先度は5です。
Javaでは3つの優先度レベルが定義されています。最低優先度(1)、通常優先度(5)、最高優先度(10)、コードは次のとおりです。Javaの優先順位の範囲は[1、10]であり、他の数値の優先順位を設定すると、IllegalArgumentExceptionがスローされます。
注意:コード実行の順序は、スレッドの優先順位とは関係ありません。優先度の高いスレッドは、優先度の低いスレッドよりも最初にCPUリソースを取得する可能性が高くなります。優先度の高いものは高速で実行されます

8.スレッド化の基本的な方法

ここに画像の説明を挿入

1.currentThread()メソッド:どのスレッドがリターンコードを呼び出しているか(現在のスレッドを取得)

public class CurrentThreadTest {
    
    
    public static void main(String[] args) {
    
    
        MyThread myThread = new MyThread();
        myThread.start();
    }
}
class MyThread extends Thread{
    
    
    public MyThread(){
    
    
        System.out.println("构造方法的打印:"+Thread.currentThread().getName());
    }
    public void run(){
    
    
        System.out.println("run方法的打印:"+Thread.currentThread().getName());
    }
}

出力結果:ここに画像の説明を挿入
実行結果からわかります。MyThread.javaクラスのコンストラクターはメインスレッドによって呼び出され、runメソッドはThread-0のスレッドによって呼び出されます
。1の2.isAlive()メソッド現在のスレッドが生きているかどうか判断することです。

public class IsAliveTest {
    
    
    @SneakyThrows
    public static void main(String[] args) {
    
    
        MythreadIsAlive myThread = new MythreadIsAlive();
        System.out.println("begin =="+myThread.isAlive());
        myThread.start();
        System.out.println("end =="+myThread.isAlive());
        //主线程睡眠1s 目的:让子线程结果
        Thread.sleep(1000);
        System.out.println("睡玩之后end =="+myThread.isAlive());
    }
}
class MythreadIsAlive extends Thread{
    
    

    @Override
    public void run() {
    
    
        System.out.println("run="+this.isAlive());
    }
}

出力結果:ここに画像の説明を挿入
つまり、アクティブステータス何?スレッドが開始され、まだ終了していない状態がアクティブ状態です
。3。sleep(Longミリ秒)メソッド:現在の「実行中のスレッド」を指定された時間(ミリ秒)内にスリープします。この実行中のスレッドはthis.currentThread()を参照します。返されるスレッド
4.stackTraceElement [] getStackTrace()メソッド:スレッドを表すスタックトレース要素グループを返します。スレッドが開始されていないか終了している場合、メソッドは長さゼロの配列を返します。返される配列の長さがゼロでない場合、最初の要素はスタックの最上位を表します。これは、配列内の最新のメソッド呼び出しです。最後の要素は、スタックの最下部を表します。これは、配列
5.static void dumpStack()メソッドで最も古いメソッド呼び出しです。この関数は、現在のスレッドのスタックトレース情報を標準エラーストリームに出力します。
6.static Map <Thread、StackTraceElement []> getAllStackTraces()メソッド:この
関数は、すべてのアクティブなスレッドのスタックトレースのマップを返します
。7.getId()メソッド:スレッドの一意の識別子を取得します
。8.yield() :現在のcpuリソースを放棄し、CPU実行時間を占有するために他のタスクにそれを放棄しますが、放棄する時間は不確実です。それはただ放棄してCPUタイムスライスをすぐに取得する可能性があります
9.interrupt():停止マーク現在のスレッドでマークされていますスレッドを実際に停止しているわけではありません
10.interrupted():現在のスレッドが中断されているかどうかをテストします実行後、ステータスフラグをfalseにクリアする機能があります// public static boolean Interrupted( )
11.isInterrupted():スレッドが中断されたかどうかをテストしますが、ステータスフラグをクリアしません// public boolean isInterrupted()
12.suspend():スレッドを一時停止します
13.resume():スレッドを再開します

おすすめ

転載: blog.csdn.net/f_a_ker/article/details/114003842