Javaのマルチスレッドプログラミング - ベースの学習

1.基本概念

次は、プロセスとスレッドが何であるかを理解するために開始しますか?それらの間の関係は何ですか?

  • プロセス:プロセスは、プログラムのインスタンスを実行している:、プロセスは、オペレーティング・システムへのアプリケーションプログラムである(例えば、実行中のEclipseはプロセスである)、(例えば、メモリ、ファイルハンドルなど)リソースの基本単位です。
  • スレッド:スレッドは、操作のスケジューリングが可能なオペレーティングシステムの最小単位です。
  • 関係:プロセスが複数のスレッドを含めることができ、スレッドは、そのようなメモリ空間、ファイルハンドルなどとして、リソースのすべてのための同じプロセスを変更するプロセスを共有しています。

複数のスレッドを使用する利点:

  • 当社のマルチコアシステムでは、CPUの使用率を向上させるための利点を取ることができます。
  • システムのスループットを向上させる、スレッドので、I / O操作と他のスレッドがまだその操作を行うことができます待っています。
  • Webアプリケーション、遅く、他の要求の動作に影響を与えない要求のため、より多くの応答。

2.スレッドの作成および開始

スレッドを作成する方法は2つあります。

  • Threadクラスの継承
  • Runnableを実装します
Threadクラスの継承

次のコードはスレッドを作成して開始するThreadクラスの道のサブクラスを定義することです。

public class CreateThreadDemo {
    public static void main(String[] args) {
        //创建线程
        MyThread myThread = new MyThread();
        //启动线程
        myThread.start();
    }
}

// 定义Thread类的子类
class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println("myThread begin running, threadName:" + Thread.currentThread().getName());
    }
}
Runnableを実装します

次のコードはスレッドを作成して開始するために、Runnableインタフェースを達成するための方法です。

public class CreateThreadByRunnable {
    public static void main(String[] args) {
        //创建线程
        Thread myThread = new Thread(new MyTask());
        //启动线程
        myThread.start();
    }
}

// 实现Runnable接口
class MyTask implements Runnable{
    @Override
    public void run() {
        System.out.println("myThread begin running, threadName:" + Thread.currentThread().getName());
    }
}

3.一般的な方法

次の表に、一般的な方法スレッドのいくつか:

方法 機能 リマーク
currentThread コードの現在の実行スレッドを返します。 コードの同じ部分()にThread.currentThreadの呼び出し、戻り値は異なるスレッドに対応することができます
産出 現在のスレッドは中断され、現在のスレッドをもたらすことができる、治療の占領を放棄します この方法は、現在のスレッドがまだ実行し続けることが、信頼性と呼ばれていません
睡眠 現在のスレッドは、指定された時間をスリープ状態に
開始 対応するスレッドを起動します スレッドのインスタンスメソッドは一度だけ呼び出すことができます開始、複数の呼び出しがスローされた例外が発生することができます
ラン タスク処理ロジックは、スレッドを実装するために Java仮想マシンによって直接呼び出され、アプリケーションが一般呼び出してはいけません
割り込み 割り込みスレッド スレッドの割り込みフラグがfalseに設定されています
中断されました 現在のスレッドが状態で中断され、スレッドの割り込みステータスをクリアするかどうかを決定します
isInterruptedを 休憩に呼び出したスレッドかどうかを確認 割り込みに応答して、この方法でスレッド
getName スレッドの名前を取得します。
加わります 対応するスレッドの実行の終了を待っています スレッドAスレッドBがメソッドを呼び出した場合は、実行スレッドAは、スレッドBの実行が終了することを知って、中断されます
getId スレッド識別子を取得します。

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

下に示すように、ライフサイクルを通じてその実行の開始から終了まで作成されたスレッドは、いくつかの状態を通過することがあります。
ここに画像を挿入説明

  • NEW:スレッドが唯一の一度だけこの状態で可能なすべての後に開始することができますので、作成されています(呼び出しスレッドのstartメソッド)、この状態でスレッドを開始していません。
  • RUNNABLE:この状態は、2つのサブ状態を含む、複合状態とみなし、Reayのを実行することができます。READYは、スケジューリングがRUNNING状態に入るためのスレッドスケジューラかもしれ表します。スレッドは、Thread.yield()メソッドにRUNNING状態READY状態に変更することができます。
  • BLOCKED:1つのスレッドは、ブロッキングIO操作を開始、または排他的なリソースの申請、ロックを取得していない、ブロックBLOCKED状態に入ったとき。IO動作を遮断した後に完了したか、ロック、RUNNABLEに、状態を取得します。
  • WAITING:スレッドははObject.wait()またはLockSupport.part(Object)メソッドを実行すると、それは待ち状態になります。この状態は、別のスレッドによって起こされなければならないObject.notify()/ LockSupport.unpart(Object)メソッドをコールし、従って再び実行可能状態に変換されます。
  • TIMED_WAITING:スレッドはのThread.sleep(ロング)、はObject.waitを(長い呼び出すと )、 (長い)LockSupport.parkNanosおよび他の方法の後、TIMED_WAITINGの時間制限、満たすために待機時間、意志で待機状態になります自動的に実行可能状態に変換。
  • TERMINATED:糸の端がTERMINATED状態で行われています。スレッドだけなので、一度だけこの状態ではすべての可能いったん開始することができます。

5.糸切れ

何中断されました

オフは、別のスレッド(ターゲット・スレッド)のスレッド(スレッド開始)によって送信された指標として見ることができ、表示はその動作が行われて停止するスレッド願いを開始するためにターゲット・スレッドを示すために使用されます。
中断しただけターゲット・スレッド自体に依存して、対象のスレッドスレッドの要求を満たすことができたスレッドに代わって発足アピールし、この需要を満たすことができる開始され、それは単にスレッドによって開始の要求を無視することができます。

使用

次のコードを見てください:

public class ThreadInterrupt {
    public static void main(String[] args) {
        // 创建子线程
        Thread myThread = new Thread(new InterruptTask());
        // 启动子线程
        myThread.start();
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 中断子线程
        myThread.interrupt();

    }
}

// 实现Runnable接口
class InterruptTask implements Runnable{
    @Override
    public void run() {
        // while条件是检测当前线程是否被中断
        while(!Thread.currentThread().isInterrupted()){
            System.out.println("thread is running...");
        }
    }
}
  • 割り込み()メソッドを呼び出すことによって、子スレッドのメインスレッドは、フラグ、割り込み子スレッドがtrueに設定されています。
  • それが中断された検出された場合()。isInterruptedを()にThread.currentThreadを呼び出すことにより、自身の子スレッド割り込みフラグ値を取得し、応答が未処理であってもよいです。
割り込み応答

割り込みに応答を阻止するための多くのJavaの標準ライブラリのメソッドはInterruptedExceptionある例外をスローしています。
私たちは、例外がスローされた後、割り込みフラグが(スレッドフラグがtrueからfalseにリセットされ、割り込み)がクリアされていることに注意する必要があります。我々は、次の例を見て:

public class ThreadInterrupt {
    public static void main(String[] args) {
        // 创建子线程
        Thread myThread = new Thread(new InterruptTask());
        // 启动子线程
        myThread.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 中断子线程
        myThread.interrupt();

    }
}

// 实现Runnable接口
class InterruptTask implements Runnable{
    @Override
    public void run() {
        try {
            // 子线程挂起3秒
            Thread.sleep(3000);
        } catch (InterruptedException e) {
        	System.out.println("子线程中断标记:" + Thread.currentThread().isInterrupted());
            e.printStackTrace();
        }
    }
}

プログラムの結果後:

子线程中断标记:false
java.lang.InterruptedException: sleep interrupted
	at java.lang.Thread.sleep(Native Method)
	at com.demo.InterruptTask.run(ThreadInterrupt.java:26)
	at java.lang.Thread.run(Thread.java:745)

私たちは、子スレッドは、プロセス内のメインスレッドがハングで中断スローされた例外:InterruptedException例外と割り込みフラグがfalseにリセットされている参照してください。
割り込みフラグがリセットされているので、我々は適切に処理されていない場合は、次の例を見ていくつかの問題を引き起こすことがあります。

public class ThreadInterrupt {
    public static void main(String[] args) {
        // 创建子线程
        Thread myThread = new Thread(new InterruptTask());
        // 启动子线程
        myThread.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        // 中断子线程
        myThread.interrupt();

    }
}

// 实现Runnable接口
class InterruptTask implements Runnable{
    @Override
    public void run() {
        // 业务方法挂起期间被中断
        service();
        if(Thread.currentThread().isInterrupted()){
            System.out.println("子线程被中断了");
        }else{
            System.out.println("子线程未被中断");
        }
    }

    // 子线程执行的业务方法
    public void service(){
        try {
            // 这边模拟子线程在执行的过程中挂起
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
            // 这边捕获到异常什么也不做
        }
    }
}

上記の例では、我々はInterruptedExceptionある異常取り込むとき、私たちは、ここでは何もしませんでした呼び出し側につながる障害が発生した論理で、その結果、正しい割り込みフラグを決定することはできません(中断フラグをfalseにリセットされます)を示しています。我々は、次の方法で対処することができます:

	// 子线程执行的业务方法
    public void service(){
        try {
            // 这边模拟子线程在执行的过程中挂起
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
            // 保留线程中断标记
            Thread.currentThread().interrupt();
        }
    }

Thread.currentThread()を呼び出すことによって、キャプチャInterruptedExceptionある例外の後。割り込み()メソッドは、呼び出し側は、それが中断され、現在のスレッドを知ることができるように、割り込みフラグを保持します。

6.待ち(待機)/通知(通知)

Javaでは、はObject.waitとObject.nofityは実装し、通知するために使用されます。Object.wait役割は(WAITINGにライフサイクル状態)に懸濁されたスレッドを実行するようにされ、待機を達成するために使用することができる。Object.notify役割は、メソッドを呼び出し、一時停止するスレッドを起動することで通知を実現することができます。私たちは、使用になります:

public class ThreadWaitNofity {
    public static void main(String[] args) {
        Object o = new Object();
        // 新建一个等待线程
        Thread waitThread = new Thread(() -> {
            // 注意:Object.wait方法只能在synchronized块中执行
            synchronized (o){
                try {
                    System.out.println("线程进入了等待,开始等待时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
                    o.wait();
                    System.out.println("线程被唤醒了,被唤醒时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    // 恢复线程中断标记
                    Thread.currentThread().interrupt();
                }
            }
        });

        // 新建一个通知线程
        Thread notifyThread = new Thread(() -> {
            try {
                // 延迟3秒钟
                Thread.sleep(3000);
                // 注意:Object.notify方法只能在synchronized块中执行
                synchronized (o){
                    o.notify();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        // 启动等待线程
        waitThread.start();
        // 启动唤醒线程
        notifyThread.start();
    }
}

結果は以下の通りであります:

线程进入了等待,开始等待时间:2020-03-11 14:49:14
线程被唤醒了,被唤醒时间:2020-03-11 14:49:17

次のように睡眠とwaitメソッドの方法の違いについては、多くの場合、面接で聞かれ、私たちは、要約しました:

待つ 睡眠
制限事項 この方法は、同期で同期だけを待って呼び出すことができます 同期にコールする必要はありません
オブジェクトの役割 waitメソッドは、オブジェクト自体に作用する、Objectクラスで定義されています スレッドで定義された睡眠方法、現在のスレッドの役割
リリースロックリソース ロックを解除 ロックを解除しないでください。
ウェイク条件 他のスレッドが呼び出したオブジェクトのは、notify()あるいはnotifyAll()メソッド タイムアウトまたは割込み
メソッドプロパティ この方法の例としては、待ち時間であります 睡眠は、静的メソッドであります
リリース7件のオリジナルの記事 ウォンの賞賛3 ビュー2101

おすすめ

転載: blog.csdn.net/ym572170/article/details/104790598