【Javaベース】マルチスレッド


スレッドとプロセスの違い
スレッドは軽量レベルのプロセスとも呼ばれ、プログラム実行の最小ユニットである.4つのステータスがあります.実行、準備、停止、終了です.1つのプロセスには、開いているファイル、コードセグメント、データセグメント、スタックスペースなどのプロセスのリソースを共有する複数のスレッドがあります.
スレッドを使用する利点は、1.より良いインタラクティビティでは、GUIプログラムでは、単一のスレッドを操作するのに時間がかかり、プログラムがより良いインタラクティビティを持つことができます.2.プロセスに比べて、スレッドのオーバーヘッドがより小さく、マルチスレッドはデータ共有の面でより便利で、効率が高い.マルチスレッドは、マルチCPUまたはマルチコアの並列実行能力4を十分に利用することができる.マルチスレッドは、プログラムの構造をより簡素化し、プログラムの理解とメンテナンスをより利用することができます.複雑なタスクのプロセスを複数のスレッドに分解
同期と非同期
簡単に言えば、同期には結果を待つ必要がなく、待機があります.したがって、同期を実現するためには、スレッドオブジェクトのロックを取得する必要があり、他のロックを同時に取得したいオブジェクトは、ロックが解放されるまで待つしかありません.同期を実装するには、同期コードブロックを用いて実装してもよいし、同期方法を用いて実装してもよい.同期は往々にしてシステムのボトルネックをもたらすので、できるだけ無駄な同期を避ける.
非同期は、各スレッドに実行時に必要なデータがあり、IOを行う際に他のスレッドの結果や状態を待つ必要がなく、IOが完了してから戻る必要もないなど、非ブロックの考え方で理解できます.
Javaマルチスレッド実装方式
主に3種類あり、Threadを継承し、Runnableを実現し、Callable 1を実現する.Threadを継承しrun()メソッドを書き換える:スレッドクラスを新規作成した後、スレッドを新規作成してstart()メソッドを呼び出します(このメソッドはスレッドを準備完了にするだけです).呼び出し後はすぐに実行されるのではなく、OSのスケジューリングを待つ2.Runnableインタフェースを実装する2.一般的なメソッドは、Threadを実装するのと似ていますが、一歩増えただけです.(このRunnableインタフェースを実装するクラスをThreadのパラメータとしてスレッドをインスタンス化し、残りは1と同じ)3.Callableインタフェース書き換えcallメソッドを実装する:Callableは実際にExecutorフレームワークのクラスであり、機能はRunnableより強い.
Callableインタフェースを実現する機能は以下の通りである.Callableインタフェースのcallメソッドは、実行が完了すると結果を返します.callメソッドは異常3を放出することができる.CallableでFutureオブジェクトが得られ、Futureは非同期計算結果のオブジェクトであり、計算が完了したかどうかを確認するために使用できます.
例:

    class MyThread1 extends Thread{
    public void run(){
        System.out.println("hello world 1");
        }
    }

    class MyThread2 implements Runnable{

        @Override
        public void run() {
            System.out.println("hello world 2");
        }
    }

    class MyThread3 implements Callable<String>{

        @Override
        public String call() throws Exception {

            return "hello world 3";
        }

    }

    public class hello {

        public static void main(String[]  args){
            // Thread
            MyThread1 thread1 = new MyThread1();
            thread1.start();

            // Runnable
            MyThread2 thread2 = new MyThread2();
            Thread t = new Thread(thread2);
            t.start();

            // Callable
            ExecutorService threadPool = Executors.newSingleThreadExecutor();
            Future<String> future = threadPool.submit(new MyThread3());
            try {
                System.out.println(future.get());
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }

        }
    }

run()とstart()
Threadクラスのオブジェクトはstart()もrun()も呼び出すことができるが,両者には本質的な違いがある.run()のみを呼び出す場合、通常のメンバーメソッド呼び出しとは異なり、マルチスレッドは開かれません.一方、start()メソッドを呼び出すと、新しいスレッドが非同期で開き、JVMスケジューリングによって実行されるのを待ち、スケジューリング実行中にrun()実行ロジックが呼び出され、run()実行が完了するとスレッドが終了します.
簡単な例で検証できますが、マルチスレッドを始めたばかりのときはいつもお互いを区別できません.
スレッド同期方法
Javaは3種類のスレッド同期メカニズムを提供した:1.synchronizeキーワード:コードブロックもメソッドも修飾できます.Javaの各オブジェクトにはオブジェクトロックがあり、synchronizeで修飾された後、同期コードブロックを実行するには、オブジェクトのオブジェクトロックを取得する必要があります.2.wait()およびnotify():同期コードブロックが実行される間、同じオブジェクトロックを取得したい他のスレッドは、wait()を待機に呼び出し、notify()またはnotifyAll()で起動し、解放されたロックを取得することができる.3.Lockインタフェースと実装クラスReentrantLock実装クラス:Lockはマルチスレッドの同期を実現するためのさまざまな方法を提供します.1)lock()ブロック方式でロックを取得し、ロックを取得したら直接戻り、そうでなければ取得まで待つ.2)tryLock():非ブロック方式でロックを取得し、取得に成功した場合、trueを返します.そうでなければfalseを返します.3)tryLock(long timeout, TimeUnit unit);与えられた時間内にロックを取得しようとし、指定された時間内に取得するとtrueを返します.そうしないとタイムアウトfalseになります.4)lockInterruptibly():ロックを取得するとすぐに戻り、取得ロックまたは現在のスレッドが別のスレッドによって中断されるまでスレッド状態がスリープになります(すなわち、lockに基づいて割り込み起動が加えられます).
sleep()とwait()
両方の方法は、現在のスレッドを一時停止して実行する方法です.違いは以下の通りである:1.原理面:sleep()はThreadの静的方法であり、スレッド自体がフロー制御を行う方法であり、本スレッドを一時停止し、他のスレッドに実行機会を与え、睡眠時間が来た後、自動的に起動する.wait()はObjectのメソッドに属します.プロセス間同期または通信に使用され、この方法は、notifyまたはnotifyAllによって起動されるまで、オブジェクトロックを現在持っているスレッドを待機させる.2.ロックの処理について:sleepは本スレッドの実行を一時停止するだけであり、スレッド間の同期や通信には関与しないため、ロックは解放されない.wait()呼び出し後、呼び出しスレッドはロックを解放する、他のスレッドは同期コードブロック3を実行することができる.使用領域:sleep()は特殊な機能の方法のように、どこでも使用できますが、wait()はスレッド同期に使用されるので、同期方法または同期文ブロックで使用されます.
注意:sleep()呼び出し時には、interrpt()によって中断されてInterruptExceptionが発生する可能性があるため、例外をキャプチャする必要があります.
補足:sleep()とyield()の違い1.sleepがスレッドを一時停止すると、優先度を考慮せずにすべてのスレッドに実行機会を譲ります.yieldは、同じ優先度またはより高い優先度のスレッドに実行機会を与えるだけです.2.sleepは現在のスレッドをブロック状態にするので、sleep()後のスレッドは指定時間内に実行されないが、yield()は現在のスレッドを実行可能状態に譲歩させるだけで、すぐに実行をスケジュールされる可能性がある.sleep()は異常を放出しますが、yield()はできません.同時にyieldはシステムに関連しているため、移植性が悪いです.
スレッドを終了する方法
Javaでスレッドを終了する方法はstop()とsuspend()である.stop停止を呼び出すと、ロックされたすべてのリソースが解放され、stopを使用すると不一致状態になり、プログラムが不安定になる可能性があります.suspendを使用すると、ロックが解放されないため、デッドロックになる可能性があります.安全なエンドスレッドの1つの方法は、スレッドを自然に終了させ、run()の実行を終了させ、スレッドを終了させることである.たとえば、run()を書き換えるときにメソッドにwhile(flag)と書く場合、他のスレッドでflagを変更することでrunの実行を制御できます.終了するスレッドが現在スリープ状態である必要がある場合、flagを変更しても何の役にも立たない場合、interrut()割り込み起動により、対応するrun()で割り込みイベントのキャプチャを実現し、終了ロジックを実行する必要がある.