Javaコンカレントプログラミングでのマルチスレッド

単一要素の最小次数を調整しオペレーティングシステムワイヤードライブです

プロセス内に複数のスレッドを作成できます。これらのスレッドには、独自のカウンター、スタック、およびローカル変数があり、共有メモリ変数にアクセスできます。プロセッサはこれらのスレッドを高速でオンにし、これらのスレッドが同時に実行されているように感じさせます。

スレッドの優先度

オペレーティングシステムは基本的に、実行中のスレッドを時分割の形式でスケジュールします。オペレーティングシステムはタイムスライスを1つずつ割り当て、スレッドには複数のタイムスライスが割り当てられます。スレッドのタイムスライスが使い果たされると、スレッドスケジューリングが発生し、次の割り当てを待ちます。スレッドに割り当てられたタイムスライスは、スレッドが使用するプロセッサリソースの量も決定します。スレッドの優先度は、スレッドが一部のプロセッサリソースを割り当てる必要があるかどうかを決定するスレッド属性です。

Javaスレッドでは、優先度の範囲は1〜10で、デフォルトの優先度は5です。優先度の高いスレッドには、優先度の低いスレッドよりも多くのタイムスライスが割り当てられます。

スレッドステータス

public class ThreadState {


    private static Lock lock = new ReentrantLock();


public static void main(String[] args) {

//线程被构建,处于NEW状态

Thread thread=new Thread(new TimeWaiting(), "TimeWaitingThread");

//线程开始,即将进入RUNNABLE状态

        thread.start();

        new Thread(new Waiting(), "WaitingThread").start();

        // 使用两个Blocked线程,一个获取锁成功,另一个被阻塞

        new Thread(new Blocked(), "BlockedThread-1").start();

        new Thread(new Blocked(), "BlockedThread-2").start();

        new Thread(new Sync(), "SyncThread-1").start();

        new Thread(new Sync(), "SyncThread-2").start();

    }


    /**

     * 该线程不断的进行睡眠

     */

    static class TimeWaiting implements Runnable {

        @Override

        public void run() {

            while (true) {

                SleepUtils.second(100);

            }

        }

    }


    /**

     * 该线程在Waiting.class实例上等待

     */

    static class Waiting implements Runnable {

        @Override

        public void run() {

            while (true) {

                synchronized (Waiting.class) {

                    try {

                        Waiting.class.wait();

                    } catch (InterruptedException e) {

                        e.printStackTrace();

                    }

                }

            }

        }

    }


    /**

     * 该线程在Blocked.class实例上加锁后,不会释放该锁

     */

    static class Blocked implements Runnable {

        public void run() {

            synchronized (Blocked.class) {

                while (true) {

                    SleepUtils.second(100);

                }

            }

        }

    }


    static class Sync implements Runnable {


        @Override

        public void run() {

            lock.lock();

            try {

                SleepUtils.second(100);

            } finally {

                lock.unlock();

            }


        }


    }

}

jstackpidを介してスレッドの実行ステータスを分析します。

 

Javaスレッドの状態遷移

注:Javaは、オペレーティングシステムの実行状態と準備完了状態を実行状態として結合します。ブロッキング状態は、synchronizedキーワード(ロックの取得)によって変更されたメソッドまたはコードブロックに入るときにスレッドがブロックされた状態ですが、java.concurrentパッケージのLockインターフェイスが待機状態であるため、java.concurrentパッケージのLockインターフェイスでブロックされたスレッド状態は待機状態です。ブロッキングの実装には、LockSupportクラスの関連するメソッドが使用されます。

 

デーモンスレッドは、主にバックグラウンドスケジューリングとプログラムでの作業のサポートに使用されるため、一種のサポートスレッドです。Java仮想マシンにデーモン以外のスレッドがない場合、Java仮想マシンは終了します。

 

注:デーモン属性は、スレッドを開始する前に設定する必要があり、スレッドの開始後に設定することはできません。

デーモンスレッドはサポート作業を完了するために使用されますが、デーモンスレッドのfinallyブロックは、Java仮想マシンの終了時に必ずしも実行されるとは限りません。

スレッドの中断

中断は、実行中のスレッドが他のスレッドによって中断されたかどうかを示す、スレッドのフラグ属性として理解できます。割り込みは、別のスレッドがスレッドに挨拶したようなものであり、他のスレッドはスレッドのinterrupt()メソッドを呼び出すことによってスレッドに割り込みます。

スレッドは、中断されているかどうかを確認することで応答します。スレッドは、メソッドisInterrupted()を使用して、中断されているかどうかを判別します。静的メソッドThread.interrupted()を呼び出して、現在のスレッドの中断フラグをリセットすることもできます。スレッドがすでに終了状態にある場合、スレッドが中断されても、スレッドオブジェクトのisInterrupted()を呼び出すとfalseが返されます。

 

注:suspend()、resume()、およびstop()メソッドは、スレッドの一時停止、再開、および終了を完了し、非常に「人道的」です。ただし、これらのAPIは古くなっているため、お勧めしません。

 

キーワードvolatileを使用して、フィールド(メンバー変数)を変更できます。つまり、変数へのアクセスを共有メモリから取得する必要があり、その変更を共有メモリに同期的にフラッシュバックする必要があることをプログラムに通知できます。これにより、すべてのスレッドが変数にアクセスできるようになります。可視性。

キーワードsynchronizedは、メソッドを変更するため、または同期ブロックの形式で使用できます。これは主に、複数のスレッドがメソッドまたは同期ブロックに同時に存在できることを保証します。これにより、スレッドの変数へのアクセスの可視性と可視性が保証されます。独占性。

public class Synchronized {

    public static void main(String[] args) {

        // 对Synchronized Class对象进行加锁

        synchronized (Synchronized.class) {


        }

        // 静态同步方法,对Synchronized Class对象进行加锁

        m();

    }


    public static synchronized void m() {

    }

}

通過javap -v同期された.class

 Javaクラスのファイル分解機能は、逆コンパイル(つまり、javacによってコンパイルされたファイルを逆コンパイル)するか、javaコンパイラによって生成されたバイトコードを表示できます。クラスファイルを分解するために使用されます。

同期ブロックを実現するために、monitorenterおよびmonitorexit命令が使用され、同期メソッドは、メソッド修飾子のACC_SYNCHRONIZEDによって完了されます。

待機/通知メカニズム

1)wait()、notify()、notifyAll()を使用する場合は、最初に呼び出し元のオブジェクトをロックする必要があります。

2)wait()メソッドを呼び出した後、スレッドの状態がRUNNINGからWAITINGに変わり、現在のスレッドがオブジェクトの待機キューに配置されます。

3)notify()またはnotifyAll()メソッドが呼び出された後も、待機中のスレッドはwait()から戻りません。notify()またはnotifAll()を呼び出すスレッドがロックを解放した後、待機中のスレッドはwait()から戻る機会があります。

4)notify()メソッドは、待機キュー内の待機スレッドを待機キューから同期キューに移動し、notifyAll()メソッドは、待機キュー内のすべてのスレッドを同期キューに移動します。移動されたスレッドの状態は、によって決定されます。 WAITINGがブロックされます。

5)wait()メソッドから戻ることの前提は、呼び出し元オブジェクトのロックを取得することです。

public class WaitNotify {

    static boolean flag = true;

    static Object  lock = new Object();


    public static void main(String[] args) throws Exception {

        Thread waitThread = new Thread(new Wait(), "WaitThread");

        waitThread.start();

        TimeUnit.SECONDS.sleep(1);


        Thread notifyThread = new Thread(new Notify(), "NotifyThread");

        notifyThread.start();

    }


    static class Wait implements Runnable {

        public void run() {

            // 加锁,拥有lock的Monitor

            synchronized (lock) {

                // 当条件不满足时,继续wait,同时释放了lock的锁

                while (flag) {

                    try {

                        System.out.println(Thread.currentThread() + " flag is true. wait @ "

                                           + new SimpleDateFormat("HH:mm:ss").format(new Date()));

                        lock.wait();

                    } catch (InterruptedException e) {

                    }

                }

                // 条件满足时,完成工作

                System.out.println(Thread.currentThread() + " flag is false. running @ "

                                   + new SimpleDateFormat("HH:mm:ss").format(new Date()));

            }

        }

    }


    static class Notify implements Runnable {

        public void run() {

            // 加锁,拥有lock的Monitor

            synchronized (lock) {

                // 获取lock的锁,然后进行通知,通知时不会释放lock的锁,

                // 直到当前线程释放了lock后,WaitThread才能从wait方法中返回

                System.out.println(Thread.currentThread() + " hold lock. notify @ " + new SimpleDateFormat("HH:mm:ss").format(new Date()));

                lock.notifyAll();

                flag = false;

                SleepUtils.second(5);

            }

            // 再次加锁

            synchronized (lock) {

                System.out.println(Thread.currentThread() + " hold lock again. sleep @ "

                                   + new SimpleDateFormat("HH:mm:ss").format(new Date()));

                SleepUtils.second(5);

            }

        }

}

WaitThreadは、最初にオブジェクトのロックを取得し、次にオブジェクトのwait()メソッドを呼び出します。これにより、ロックが解除され、オブジェクトのWaitQueueに入り、待機状態になります。WaitThreadがオブジェクトのロックを解放したため、NotifyThreadはその後オブジェクトのロックを取得し、オブジェクトのnotify()メソッドを呼び出して、WaitThreadをWaitQueueからに移動しました。

SynchronizedQueueでは、この時点でWaitThreadのステータスがブロックされます。NotifyThreadがロックを解放した後、WaitThreadは再びロックを取得し、wait()メソッドから戻って実行を続行します。

Thread.join()

現在のスレッドAは、thread.join()から戻る前に、スレッドスレッドが終了するのを待ちます。

ThreadLocal

これは、ThreadLocalオブジェクトをキーとして、任意のオブジェクトを値として持つストレージ構造です。この構造はスレッドにアタッチされます。つまり、スレッドはThreadLocalオブジェクトに基づいてこのスレッドにバインドされた値を照会できます。

おすすめ

転載: blog.csdn.net/weixin_44416039/article/details/86160970