Android/javaマルチスレッド(一)-threadの使用とソースコード分析

6657 ワード

スレッドの概念とステータス
スレッドを学習する前に、各プログラムの実行には親プロセスがあり、私たちのスレッドはこの親プロセスで実行されます.Androidでは、デフォルトでは、すべてのコンポーネントプログラムが同じプロセスで実行され、実行スレッドが作成されます.このプロセスでは、通称「メインスレッド」と呼ばれています.このスレッドで時間のかかる操作をしてプログラムカートンを作成した場合、「スレッドブロック」と呼ばれます.この場合、別のスレッドを作成して時間のかかる操作を実行する必要があります.
スレッド内のメソッドの使用を理解するには、スレッドの実行状態を理解する必要があります.スレッドの作成から実行まで、合計6つのステータスがあります.
  • NEW(スレッド作成未起動)
  • RUNNABLE(実行中のスレッド)
  • BLOCKED(ブロックされ、モニタロックの解放を待つ)
  • .
  • WAITING(起動待ち)
  • TIMED_WAITING(待機または一定時間の睡眠が覚醒)
  • TERMINTED(スレッド終了、消滅)
  • これらの状態はThreadのソースコードのStateの列挙に対応し、getState()の方法によってスレッドの実行状態を取得することができる.
    このうちBLOCKEDはモニタロックを待つプロセスを示しているが、モニタロックとは何か、モニタロックはスレッドの不安全を解決するために誕生した方法であり、複数のプロセスが1つのデータ構造を同時に操作して修正すると、データ構造が不確定になり、「スレッドが不安全」と呼ぶ.そこで、synchronized( )lock などのメカニズムを使用して、このスレッドが安全ではないことを解決し、このロックを装着すると、現在1つのスレッドだけがこのデータ構造を修正することができ、他のスレッドは待つ必要があります.これはデータ構造の一致性を保証し、他のスレッドは待機状態、つまり私たちのBLOCKED状態に入ります.synchronizedの使用例:
        class MyThread extends Thread {
    
            @Override
            public void run() {
                synchronized (this) {
                    //           
                }
            }
        }
    
    lockの使用例:
        class MyThread extends Thread {
            private final ReentrantLock lock = new ReentrantLock ();
            
            @Override
            public void run() {
                lock.lock();
                    //           
                lock.unlock();
            }
        }
    

    もちろん,両者の応用はスレッドだけでなく,必要なメソッド呼び出しにも用いられる.
    スレッドのソースコードおよびメソッドの使用Threadソース:
    public class Thread implements Runnable {
     ...........
        /* Some of these are accessed directly by the VM; do not rename them. */
        private volatile long nativePeer;
        volatile ThreadGroup group;
        volatile boolean daemon;
        volatile String name;
        volatile int priority;
        volatile long stackSize;
        Runnable target;
        private static int count = 0;
        private long threadInitNumber ;
    
        /**
         * Normal thread local values.
         */
        ThreadLocal.Values localValues;
    
        /**
         * Inheritable thread local values.
         */
        ThreadLocal.Values inheritableValues;
    
        /** Callbacks to run on interruption. */
        private final List interruptActions = new ArrayList();
    
        /**
         * Holds the class loader for this Thread, in case there is one.
         */
        private ClassLoader contextClassLoader;
    
        /**
         * Holds the handler for uncaught exceptions in this Thread,
         * in case there is one.
         */
        private UncaughtExceptionHandler uncaughtHandler;
    
        /**
         * Holds the default handler for uncaught exceptions, in case there is one.
         */
        private static UncaughtExceptionHandler defaultUncaughtHandler;
    
       .....
    }
    

    ThreadはRunnableインタフェースを実装し、いくつかのスレッドでよく使用される変数を宣言しました.
  • groupスレッドグループ、スレッドグループは他のスレッドグループを含み、ツリー構造を形成している.初期のスレッドグループを除いて、他のスレッドグループには親プロセスがあり、スレッドは現在のスレッドグループの情報にアクセスできるが、親スレッドグループの情報
  • にアクセスできない.
  • daemonはデーモンスレッドかどうか、デーモンスレッドとは何か、デーモンスレッドはそのスレッドを作成することに依存するスレッドの一種であり、一般的なスレッドとは異なり、そのスレッドを作成して閉じると閉じられるが、一般的なスレッドではなく、私たちのゴミ収集器スレッドのようにデーモンスレッド
  • である.
  • threadInitNumber現在のスレッドの識別子であり、スレッドの作成順序に従って重畳された
  • である.
  • nameスレッドの名前は、指定されていなければ"Thread-" + threadInitNumberの論理で
  • と命名される.
  • priorityスレッド優先度は、3つの状態MIN_PRIORITYNORM_PRIORITYMAX_PRIORITYがあり、それぞれ低、中、高
  • に対応する.
  • stackSizeスタックサイズ
  • target現在のターゲットスレッド
  • contextClassLoaderクラスローダは、このスレッドの情報を保存するためのものであり、ブレークポイント再送などの機能は
  • に使用することができる.
  • uncaughtHandlerスレッドは例外呼び出しクラスをキャプチャしていません.設定していない場合は、デフォルトでdefaultUncaughtHandlerを使用して例外を処理します.メインスレッドもThreadなので、UncaughtExceptionHandlerインタフェースを実装し、Thread.setDefaultUncaughtExceptionHandler()メソッドを呼び出すことで、カスタム例外取得クラスをThreadに設定することができます.これにより、グローバルな例外
  • をキャプチャできます.
    いくつかの一般的な変数を理解した後、いくつかの一般的な方法を見てみましょう.
    start()メソッド
    スレッドを起動するには、このメソッドを呼び出すだけで、スレッドが新たに開き、必要なリソースに割り当てられます.Threadの構造方法を見てみると、最終的にはinitメソッドが呼び出され、基本変数を初期化するだけで、リソースに割り当てられていないことがわかりました.
        private void init(ThreadGroup g, Runnable target, String name, long stackSize) {
            Thread parent = currentThread();
            if (g == null) {
                g = parent.getThreadGroup();
            }
    
            g.addUnstarted();
            this.group = g;
    
            this.target = target;
            this.priority = parent.getPriority();
            this.daemon = parent.isDaemon();
            setName(name);
    
            init2(parent);
    
            /* Stash the specified stack size in case the VM cares */
            this.stackSize = stackSize;
            tid = nextThreadID();
        }
    

    したがって、新しいスレッドを作成してもリソースは消費されず、star後にのみ必要なリソースが割り当てられます.このとき、スレッド状態はNEWからRUNNABLEに変わります.
    run()メソッド
    このメソッドはスレッドで実行される論理を処理するために使用され、Threadクラスを継承する場合はメソッドを書き換える必要があります.
    sleep()メソッド
    sleep(long millis)     //     
    sleep(long millis,int nanoseconds)    //       ,        
    

    スレッドをしばらくスリープさせることは、スレッドをブロック状態にすることに相当します.スレッドがスリープしてもロックメカニズムが有効であっても、他のスレッドはオブジェクトロックが解放されるまでロックされたデータ構造にアクセスできません.このとき、スレッド状態はRUNNABLEからTIMED_WAITINGに入ります.
    yield()メソッド
    現在のスレッドに対応する権限を与え,他のスレッドに譲歩させることは,CPUの過度な使用を防止する有効な手段である.効果はsleepとさほど差はないが、具体的な時間を指定することができず、スレッドをブロック状態にするのではなく、準備完了状態にする.このときスレッド状態はRUNNABLEからWAITINGに入る.
    join()メソッド
    join()
    join(long millis)     //     
    join(long millis,int nanoseconds)    //       ,        
    

    この方法は、スレッドを優先して実行することです.残りのスレッドは、スレッドが実行されるまで停止します.スレッドを正常に走行している車両(オンラインキュー)と見なすことができます.そのうちの1台にjoin(カーブオーバー)を使用すると、残りの車は行を譲り(スレッドは一時停止状態に入ります)、優先的に走行させ(joinのスレッドが運行します)、終点に達するまで(運行が完了します)、走行を続けます(実行を続けます)joinソースコードでは呼び出されたwait()メソッドであり、wait()メソッドはスレッドをブロック状態にしてオブジェクトロックを解放することができるので、joinメソッドもオブジェクトロックを解放することができる
    interrupt()メソッド
    スレッドを中断すると,スレッドがrunメソッドを実行した論理が終了状態に入ることが分かった.このメソッドを呼び出すと、ブロックされたスレッドがInterruptedExceptionの異常を放出し、スレッドを終了します.isInterrupted()を呼び出すと、スレッドが終了したかどうかを判断できますが、ブロックされていないスレッドがどのように中断されるかを確認します.
    class MyThread extends Thread{
            private volatile boolean isStop = false;
            @Override
            public void run() {
                int i = 0;
                while(!isStop){
                    i++;
                }
            }
             
            public void setStop(boolean stop){
                this.isStop = stop;
            }
        }
    

    実行が完了したかどうかを制御してスレッドを終了する変数を設定できます.スレッド状態はTERMINATED状態に入ります.