実戦Java高同時プログラミングノート

31703 ワード

『実戦Java高同時プログラミング』ノート


Linus:The only place where parallelism matters is in graphical or the server side,where we already largely have it. Pushing it anywhere is just pointless

パラレルワールドに入ると


1.2いくつかの概念を知っておく必要があります.
同期と非同期
同期:同期呼び出しが開始されると、呼び出し元はメソッドが戻ってくるまで待たなければなりません.
非同期:非同期メソッドはメッセージングに似ており、開始するとメソッド呼び出しはすぐに戻り、呼び出し者は後続の操作を継続することができる.非同期メソッドは通常、1つのスレッドで実際に実行される.非同期呼び出しが結果を返す必要がある場合、この呼び出しが実際に完了すると、呼び出し者に通知される.
同時および並列
同時:複数のタスクの交互実行に偏る.
並列:真の意味を同時に実行する.
通常両者は区別しない.
りんかいいき
臨界領域は、共通のリソースまたは共有データを表すために用いる、複数のスレッドで使用することができるが、毎回、1つのスレッドしか使用できず、臨界領域のリソースが呼び出されると、他のスレッドがこのリソースを望むのは待つしかない.
例:プリンタ
ブロックと非ブロック
以上のように
デッドロック、飢餓、活錠
デッドロック:
飢餓:あるスレッドまたは複数のスレッドが何らかの理由で必要なリソースを得ることができず、実行できなくなった.
活鎖:もし2つのスレッドの“知能”が足りないならば、しかもすべて“謙譲”の原則を堅持して、自発的に資源を他人に放出して使用して、それでは2つの資源が絶えず2つのスレッドの間で跳躍して、1つのスレッドが同時にすべての資源を正常に実行することができません.
1.3同時性レベル
閉塞無飢餓無障害無ロック無待機1.5 JMM
原子性:1つの操作は中断できません
可視性:1つのスレッドがグローバル変数を変更すると、他のスレッドはすぐにこの変更を知ることができる.
秩序性:理解命令再配列Happen-Beforeルール:

二Java並列プログラムの基礎


2.1スレッド


スレッドの定義:
スレッドのライフサイクル:スレッドのすべてのステータスがThreadのState列挙で定義されます.
public enum State{
  NEW,
  RUNNABLE,
  BLOCKED,
  WAITING,
  TIMED_WAITING,
  TERMINATED;
}

NEWの状態は作成したばかりのスレッドを表す、このスレッドはまだ実行を開始していない.スレッドのstart()メソッドが呼び出されると、スレッドが実行を開始することを示し、スレッドが実行されるとRUNNABLE状態になり、スレッドに必要なすべてのリソースが準備されていることを示します.スレッドが実行中にsynchronized同期ブロックに遭遇すると、BLOCKEDブロック状態に入り、要求されたロック、WAITING、TIMED_を取得するまでスレッドが実行を一時停止することを示します.WAITINGはすべて待つことを表して、TIMED_WAITINGは時限のある待機を表す.待機イベントは、例えばwait()メソッドでnotify()メソッドを待ち、join()メソッドで待機スレッドはターゲットスレッドの終了を待ち、所望のイベントを待つとスレッドは再び実行され、RUNNABLE状態に入る.スレッド実行完了後、TERMINTED状態に入り、終了を示す

2.2初期スレッド

Thread t1 = new Thread();
t1.start;
Thread t1 = new Thread();
t1.run; // ,  run  , 
Thread t1 = new Thread(){
  @Override
  public void run(){
    System.out.println("Hello I am t1");
  }
} // :  Thread  
t1.start;
public class CreatThread implements Runnable{
  @Overide
  public void run(){
    System.out.println("Oh,I am Runnable!");
  }
  publc static void main(String[] args){
    Thread t1 = new Thread(new CreateThread());
    t1.start();
  }
}

2.2.2エンドスレッド


なぜ捨てた?stop()
Thread.stop()メソッドは、スレッドを終了すると、スレッドを直接終了し、そのスレッドが持つロックを直ちに解放するが、これらのロックはオブジェクトの一貫性を維持するために使用される.
スレッド割込み
スレッドの中断は、スレッドをすぐに終了させるのではなく、ターゲットスレッドに終了してほしいという通知を送信します.ターゲットスレッドが通知を受ける後にどのように処理するかは、完全にターゲットスレッドが自分で決定する.
public void Thread.interrupt() // ( , )
public boolean Thread.isIntertupted() // 
public static boolean Thread.interrupted()// , 
public class Test {
    public static void main(String[] args) throws InterruptedException {

        Thread t1 = new Thread(){
            @Override
            public void run() {
                while (true){
                    if(Thread.currentThread().isInterrupted()){
                        System.out.println(" !");
                        break;
                    }
                    try {
                        Thread.sleep(2000);// , 
                    } catch (InterruptedException e) {
                        System.out.println(" !");
                        Thread.currentThread().interrupt();
                    }
                    Thread.yield();
                }
            }
        };
        t1.start();
        Thread.sleep(2000);
        t1.interrupt();
    }
}

// : !
//		 !


待機(wait)と通知(notify)
待機メソッドと通知メソッドはThreadクラスではなく、Objectクラスにあります.これは、任意のオブジェクトがこの2つのメソッドを呼び出すことができることを意味します.
オンラインスレッドAでobjが呼び出された.wait()メソッドは、スレッドAが実行を停止する、待機状態に移行する.スレッドAは、他のスレッドがobjを呼び出すまで待機する.notify()メソッドまで.この場合、objは明らかに複数のスレッド間の通信の有効な手段となる.
Object.wait()メソッドは勝手に呼び出すことができない.彼は対応するsynchronized文に含める必要があります.waitメソッドでもnotifyメソッドでも、ターゲットオブジェクトのモニタを先に取得する必要があります.
1つのスレッドがwaitメソッドを呼び出すと、objectオブジェクトの待機キューに入り、このキューには複数のスレッドがある可能性があり、notifyメソッドが呼び出されると、この待機キューからランダムに1つのスレッドを選択し、起動する.この選択は不公平で、完全にランダムです.
注意:Object.方法と方法sleep()メソッドは、スレッドをいくつかの時間待つことができる.wait()メソッドが起動可能であることに加えて、もう一つの主な違いはwait()メソッドがターゲットオブジェクトのロックを解放し、Thread.sleep()メソッドはリソースを解放しません
2.2.6スレッド終了待ち(join)と謙譲(yield)
join():実行を続行するには、依存スレッドの実行が完了するまで待つ必要があります.
public final void join() throws InterruptedException// , 
public final synchronized void join(long millis) throws InterruptedException// 

join法の本質を分析する
public static native void yield()//  CPU,  CPU  

2.3 volatileとJMM
スレッドの安全を本当に保証することはできません.彼は1つのスレッドがデータを修正した後、他のスレッドがこの変更を見ることができることを確保するしかありません.
2.4スレッドグループ
public class ThreadGroupName implements Runnable{
    public static void main(String[] args) {
        ThreadGroup tg = new ThreadGroup("PrintGroup");
        Thread t1 = new Thread(tg,new ThreadGroupName(),"T1");
        Thread t2 = new Thread(tg,new ThreadGroupName(),"T2");
        t1.start();
        t2.start();
        System.out.println(tg.activeCount());
        tg.list();
    }

    @Override
    public void run() {
        String groupAndName = Thread.currentThread().getThreadGroup().getName()+"-"+Thread.currentThread().getName();
        while (true){
            System.out.println("I AM " + groupAndName);
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }


    }
}

2.5デーモンスレッド(Daemon)
ゴミ回収スレッドの場合、JITスレッドはいずれもデーモンスレッドと理解することができる.これに対応するユーザスレッドは、システムの動作スレッドであると理解できる.ユーザー・スレッドがすべて終了すると、このプログラムが実際には何もできないことを意味し、デーモン・スレッドがデーモンするオブジェクトが存在しなくなると、アプリケーション全体が終了する必要があります.そのため、javaアプリケーション内にデーモン・スレッドしかない場合、java仮想マシンは自然に終了します.
public class DaemonDemo{
    public static class DaemonT extends Thread{
        @Override
        public void run() {
            while(true){
                System.out.println("I AM ALIVE");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

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

        Thread t1 = new Thread(new DaemonT());
        t1.setDaemon(true);//  start() , 
        t1.start();

        Thread.sleep(2000);
    }
}



2.6スレッド優先度
high.setPriority(Thread.MAX_PRIORITY)//public final static int MIN_PRIORITY = 1
low.setPriority(Thread.MIN_PRIORITY)//10

優先度の高いスレッドは、リソースを競合する場合に優位になりますが、これは依然として確率的な問題です.
2.7 synchronizedキーワード
2.8初心者がよく犯す間違い:間違いのロック

三JDK並発注


3.1.1再入錠
ReentrantLockのいくつかの重要な方法について、以下のように整理します.
  • lock():ロックを取得し、占有されると
  • を待つ.
  • lockInterruptibly():ロックを取得するが、優先応答中断
  • tryLock():ロックを取得しようとし、成功するとtrueを返し、失敗するとfalseを返す.この方法は待たずに
  • に戻る.
  • tryLock(Long time,TimeUnit unit):所与の時間内にロック
  • を取得しようと試みる
  • unlock():リリースロック
  • 3.2.2再ロックの良いパートナー:Condition
    public class ReentrantLockCondition implements Runnable{
        public static ReentrantLock lock = new ReentrantLock();
        public static Condition condition = lock.newCondition();// condition
    
    
        @Override
        public void run() {
            try{
                lock.lock();
                condition.await();// , ,  signal() , , , 
                System.out.println("GOING ON");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    
        public static void main(String[] args) throws InterruptedException {
    
    
            Thread t1 = new Thread(new ReentrantLockCondition());
            t1.start();
            Thread.sleep(2000);
            lock.lock();
            condition.signal();
            lock.unlock();// , t1, , 
        }
    }
    
    

    3.2スレッド多重化:スレッドプール