Javaの - スレッドプールの基本

1、基本的な考え方

1、共有リソース

アクセス(読み取り又は書き込み)が同じリソースのコピーに複数のスレッドは、リソースが共有リソースとして知られています。複数のスレッドがデータにアクセスすることを確保するための方法と同じである、データ同期やリソースの同期と呼ばれています。

図2に示すように、スレッド通信

また、内部プロセス通信として知られているスレッド間通信、およびネットワーク通信処理の異なる通信、複数のスレッドが時間のリソースへの相互排他的アクセスを達成するために、それはお互いに信号を送ります。

2、同期、非同期、ブロッキング、非ブロッキング

同期および非同期の方法は、ブロッキングとノンブロッキングが他のものを完了するために、結果を待つかどうかで、結果を取得することです。

クライアントのデータを待機する同期ブロック(BIO)は、読まれた、またクライアントをブロックし、必要なデータがあるか否かを判断します。

同期非ブロッキング(NIO)は、あなたが読み込まれたクライアントのデータを待つ必要がありますが、ポーリングデータを経由して、クライアントが他のことを行うことができますかどうかを判断します。

非同期ブロック、休止状態の待機中のコールバック通知の結果、CPUののを待っています。

非同期読み取り操作を完了するために(AIO)非ブロック、オペレーティングシステム、リード完了通知コールバックは、クライアントのデータをポーリングするスレッドプールの方法を使用して、あなたは他のことを行うことができます。

同時に、単一のCPUは、複数のタスクを処理しますが、同時に実行で1つのタスクのみできます。

、複数のCPUで同じリアルタイム操作を実行するための並列複数のタスク。

2、ライフサイクル

//当new一个Thread的时候,此时只是一个简单的java对象
NEW

//调用start方法之后,进入该状态,此时只是处于可执行状态,但还未执行
RUNNABLE

//处于执行状态,可由于调用sleep/join和wait、阻塞IO操作、尝试获取锁,进入 BLOCKED 状态
//可由于cpu调度、调用yield,进入 RUNNABLE 状态
RUNNING   

//在sleep完毕和wait唤醒、阻塞IO操作完成、获得了锁、阻塞过程被interrupt,进入 RUNNABLE 状态
BLOCKED 

3、デーモンスレッド

一般的には、新しいスレッド作成したスレッドを使用しても、ユーザスレッドとして知られている非デーモンスレッド、あります。道を守るために実行する前に、(真)は、setdaemonを呼び出す、ということです。デーモンスレッド、単にユーザスレッドにサービスを提供するため、すべてのユーザー・スレッドの実行が終了したら、保護者が最後になります。逆に、限り、非デーモンスレッドが存在するとして、その後、ガードは、スレッドを終了しないでしょう。

デーモンスレッドシナリオ:ガベージコレクション、心拍検出、スペルチェックスレッド

package com.vim;

import java.util.concurrent.TimeUnit;

public class App {
    public static void main( String[] args ) throws Exception{
        Thread t = new Thread(()->{
            while (true){
                try {
                    TimeUnit.SECONDS.sleep(1);
                    System.out.println("......");
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        });
        //只有t设置了此处,才会随着父进程的退出而退出
        t.setDaemon(true);
        t.start();
        TimeUnit.SECONDS.sleep(5);
        System.out.println("main is over!");
    }
}

4、スレッド収率、睡眠

降伏した後、RUNNING状態から実行可能状態にスレッドの譲歩と呼ばれる、RUNNING状態に、執行力をつかむために再び切り替えることが可能です。

睡眠は、スレッドをブロックすることができBLOCKED状態に入り、これを懸濁し、CPUのように、唯一の遮断時間は、最大で、必ずしも直ちにCPUを実行する権利を取得しない、実行可能状態に入ります。

睡眠(0)の役割は、オペレーティング・システム、すぐに再CPUの競争、まだ現在のスレッドのCPU制御を取得競争の結果、おそらく一度トリガされ、別のスレッドで置き換えることができるには、CPUの制御を取得します。

package com.vim;

public class App {
    public static void main( String[] args ) throws Exception {
        new Thread(()->{
            try {
                while (true){
                    Thread.sleep(0);
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }).start();
    }
}

5、スレッドの割り込み

、睡眠、待ってブロックされた状態に現在のスレッドに参加し、ブロックされた中断することができ、割り込み、単に渋滞状態を提示することを意図しています。InterruptException現在のスレッドがシグナル通知として例外がスローされます。この通知は、フラグがtrueに設定されますが、ステータスビットのブロッキング状態のために中断falseにリセットされる中断されます。thread.isInterrupted()によって判断、もちろん、ブロッキング状態では、このように方法の結果に影響を及ぼし、除去されます。

package com.sample.modules.test;

import java.util.concurrent.TimeUnit;

public class Test {

    //中断一个线程,中断位 true
    public static void test1() throws Exception{
        Thread t = new Thread(()->{
            //2.获取当前的 interrupt flag 状态为 true
            System.out.println(Thread.currentThread().isInterrupted());
        });
        t.start();

        //1.中断线程
        t.interrupt();
        TimeUnit.MINUTES.sleep(4);
    }

    //中断一个线程,中断位 false
    public static void test2() throws Exception{
        Thread t = new Thread(()->{
            //2.清除中断位
            Thread.interrupted();
            //3.获取当前的 interrupt flag 状态为 false
            System.out.println(Thread.currentThread().isInterrupted());
        });
        t.start();

        //1.中断线程
        t.interrupt();
        TimeUnit.MINUTES.sleep(4);
    }

    //中断一个线程,中断位 false
    public static void test3() throws Exception{
        Thread t = new Thread(()->{
            //2.中断wait、sleep、join导致的阻塞
            try {
                TimeUnit.SECONDS.sleep(5);
            }catch (InterruptedException e){
                System.out.println("i am interrupted");
            }
            //3.获取当前的 interrupt flag 状态为 false
            System.out.println(Thread.currentThread().isInterrupted());
        });
        t.start();

        //1.中断线程
        t.interrupt();
        TimeUnit.MINUTES.sleep(4);
    }

    //阻塞之前中断结果:false、true、i am interrupted、false
    public static void test4(){
        Thread.interrupted();
        System.out.println("interrupt flag: "+Thread.currentThread().isInterrupted());
        Thread.currentThread().interrupt();
        System.out.println("interrupt flag: "+Thread.currentThread().isInterrupted());
        try {
            TimeUnit.SECONDS.sleep(1);
        }catch (InterruptedException e){
            System.out.println("i am interrupted");
        }
        System.out.println("interrupt flag: "+Thread.currentThread().isInterrupted());
    }

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

6、スレッドが参加します

親スレッドは実際にあなたが作ることができますので、もちろん、各呼び出しは、(0)メソッドサイクルを待つために、子どもの生存状況を判断するために糸ループ、ロックを追加した、(0)参加呼び出し、子スレッドは、joinメソッドを呼び出します他のスレッドも(0)メソッドに参加入力することができます。

//当前方法没有上锁
public final void join() throws InterruptedException {
    join(0);
}

//此方法上锁,此时其他线程可以进入 join(),但不可以进入 join(0)
//不断的检查线程是否 alive,调用 wait(0),这样就释放了锁,其他的线程就可以进入 join(0),也就是可以有多个线程等待某个线程执行完毕
//一旦线程不在 alive,那么就会返回到 join() 方法,调用的线程就可以继续执行下去
public final synchronized void join(long millis){
    if (millis == 0) {
         while (isAlive()) {
            wait(0);
        }
    }
}

7、スレッドの通知は、通知、待ちます

両方を使用してObjectクラスから派生これらの2つの方法、。この方法は、メソッドをオブジェクトに属し、あなたがオブジェクトのモニターロックを呼び出す前に取得する必要があります待って、コールの後、そのオブジェクトに関連するwaitsetを入力し、ウェイクを知らせる使用して他のスレッドを待機するオブジェクトのモニターロックを解除します。

典型的な生産と消費のシナリオ:

現在の倉庫が満杯になった場合、ロックを解除待っ使用、ブロックされたwaitsetを入力し、財の生産における生産現在の倉庫が満杯でない場合、倉庫(アイソクロナスリソース)が、ロックされていたが、その後、消費者に通知のnotifyAll使用するように製品を追加します通知を待つのnotifyAll。

現在の倉庫が空の場合は、ロックを解除待つwaitsetを入力を使用し、消費者、消費がプロデューサーに通知のnotifyAll使用し、製品を取る、その後、現在の倉庫の製品ならばロックする倉庫(同期リソース)、倉庫に来ました待機のnotifyAll通知を遮断します。

notifyAllが来ると、すべての生産者と消費者、倉庫を取得するための鍵を持ってする機会のために、競争は再び多くの決定ロジックになります。

8違い、待って中に眠ります

一般的には:

ブロックされた状態にスレッド、割り込み中断することができます。

違い:

待機オブジェクトは、睡眠がユニークなスレッドである、があります。

同期して実行する必要がありますプロセスを待って、睡眠が必要。

同期方法の睡眠場合は、ロックを解除します待って、ロックを解除しません。

9、例外処理スレッド

package com.sample.modules.test;

public class Test {

    public static void main(String[] args) throws Exception{
        Thread t = new Thread(()->{
            int i = 1/0;
        });
        t.setUncaughtExceptionHandler((thread, e)->{
            System.out.println("exception...");
        });
        t.start();
    }
}

10、コンピュータのメモリモデルとJavaのメモリモデル

原理遡及:命令実行時のCPU、メインメモリ(RAM)からのデータ、速度等の両方が深刻ではないために、キャッシュ・バッファとの間で発生し、一般的にL1、L2、含むCPUコア当たりのL3キャッシュに分かれ共有L1、L2およびL3キャッシュのセット。

キャッシュコヒーレンシ問題:コンピューティングタスクを複数のプロセッサは、その後、キャッシュに書き込まれ、その後、計算、ローカルキャッシュに、メインメモリから削除各CPU変数、同一の主記憶領域を参照キャッシュは、メインメモリにフラッシュ。

  • 私はキャッシュにメインメモリを読みます
  • 私がする++します
  • ライトバックキャッシュ結果
  • バックメインメモリにキャッシュを更新します。

キャッシュコヒーレンシプロトコル:共有変数が見つかった場合、キャッシュ内のCPU動作データは、その後、書き込み時に、それは他のCPUを実行し、無効化された可変CPUキャッシュラインの他に信号を送ります変数の読み取りは、あなたが読んでメインメモリに移動する必要がある場合。

比較すると、コンピュータのメモリモデル、Javaのメモリモデル:スレッド== CPU、ワーキングメモリ== CPUキャッシュ、メインメモリ==メインメモリ。

12、並行プログラミングの三の大特徴

  • アトミック、複数の操作は、いずれかのすべての実行されるか、まったく実行されません。
  • 可視性、共有変数のスレッドは、その後、他のスレッドがすぐに修正後の値を見ることができ、変更されています。
  • 秩序、オーダーの実行中のプログラム・コード。

13、synchronizedキーワード

synchronizedキーワードは、共有変数、つまり同じ時間に相互に排他的アクセスを確保するために、ロックする機構を提供し、1つのスレッドのみリソースへのアクセスを同期します。

メモリの利用規約、モニターが入る前に、いずれかのスレッドがメインメモリからデータを取得しなければならないことを確実にするために、出口2つのJVMコマンドを入力して、監視モニターは、モニター終了後、あなたは、メインメモリに更新された値を更新する必要があります。モニターがexitコマンドで指示を入力する前にJVMコマンド、厳格なコンプライアンスはhappends-前の原則の両方が、そこに存在している必要があります。

同期リソースへの排他的アクセスのためのキーワード、非常に効果的な、しかし他のスレッドを監視するために取得していない、進めることができないブロック解除どのくらいのブロッキング、最終的には、これらは不明です。この目的を達成するために、Javaは明示的に私たちのためにロックする他のソリューションを提供しています。ReentrantLockのよう。

おすすめ

転載: blog.csdn.net/sky_eyeland/article/details/93177820