Javaプロセスとスレッドの違い

51675 ワード

プロセスとスレッドの由来
プロセス:最初のコンピュータの発展の時期、すべての命令はすべてシリアルで実行して、もしユーザーIOの命令に出会うならば、システムはユーザーIOが完成した後に引き続き命令を実行して、極めて大きいCPUの時間を浪費して、この情況を緩和するために、命令セットの概念を導入して、実行する必要がある命令をすべて1つのディスクの上で書いて、オペレーティングシステムに運行させて、このようにバッチオペレーティングシステムが誕生し、次にもう一つの問題に直面した.もし一つのプログラムにタスクAとタスクBがあれば、タスクAの実行には大量のIO操作が必要であり、当時のバッチオペレーティングシステムによって、まだAを待っていて、CPU資源を浪費しているので、システムに複数のプログラムを導入しようとしたが、そのプログラムの間でどのように区別するか、プロセスの概念を導入した.便利なタスクAはIOの過程を待つ中で、タスクBはCPUを奪い取ることができて、タスクAのIOの操作が完成することを待って、Aは引き続き実行して、プロセスは資源の最小の単位のスレッドを割り当てます:スレッドはプロセスの内部の同時性のためで、プログラムの実行効率を高めます
プロセスとスレッドの違いは?
  • プロセスはシステム割当リソースの最小単位であり、スレッドはcpuスケジューリングの最小単位
  • である.
  • プロセスは独立したアドレス空間を有し、1つのプロセスは複数のスレッドを含み、複数のスレッドはアドレス空間
  • を共有する.
  • javaのプロセスはJVMオブジェクトインスタンスに対応し、複数のスレッドはjvmの
  • で実行されます.
    スレッドのStartとRunメソッドの違い
    Startメソッドは、1つのスレッドを個別に起動し、対応するRunメソッドを実行してRun()メソッドを直接呼び出します.これは、プライマリスレッドでRunメソッドを呼び出すことに相当します.
    package com.bdcloud.thread;
    
    public class ThreadTest {
    
        public static void main(String[] args) {
    
            MyThread thread = new MyThread();
            thread.run();
            System.out.println("------------------------");
            thread.start();
        }
    
    }
    class MyThread extends Thread{
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName());
        }
    }
    
    //      
    Connected to the target VM, address: '127.0.0.1:6910', transport: 'socket'
    main
    ------------------------
    Thread-0
    Disconnected from the target VM, address: '127.0.0.1:6910', transport: 'socket'
    
    Process finished with exit code 0
    
    

    マルチスレッドを実現する3つの方法
  • Thread実装runメソッド
  • を継承
  • Runableインタフェースを実現し、run方法
  • を実現する.
  • はCallableインタフェースを実現し、FutureTaskクラスを借りて、このクラスの本質はやはりRunableインタフェースを継承し、間接的にRunableインタフェース
  • を実現した.
    //Callable   
    public class MyCallbale implements Callable<String> {
    
       public String call() throws Exception {
    
           String value = "every thing";
           System.out.println("Task is Reading");
           Thread.sleep(5000);
           System.out.println("Task Done!");
           return value;
       }
    }
    
    //  Callable     
    package com.bdcloud.thread;
    
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.FutureTask;
    
    public class FeatureTaskDemo {
       public static void main(String[] args) throws ExecutionException, InterruptedException {
           FutureTask<String> futureTask = new FutureTask<String>(new MyCallbale());
           new Thread(futureTask).start();
    
           if (!futureTask.isDone()){
               System.out.println("futureTask is not down1");
           }
           System.out.println(futureTask.get());
       }
    }
    //            
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    
    public class ThreadPoolTest {
       public static void main(String[] args) throws ExecutionException, InterruptedException {
           ExecutorService executorService = Executors.newCachedThreadPool();
           Future<String> submit = executorService.submit(new MyCallbale());
           if (!submit.isDone()){
               System.out.println("futureTask is not down1");
           }
           System.out.println(submit.get());
       }
    }
    

    スレッドのステータス
  • 新規ステータス(New):スレッドは作成されますがstartメソッド
  • は実行されません.
  • 運転(Runable):2種類に分けられ、RunningとReady、Running状態はCPU使用権を取得して実行する、readyはCpu待ち時間
  • である.
  • 無線待機(Waiting):CPU実行時間が割り当てられず、例えばsynchronizeでObject.wait()メソッド
  • を呼び出すように起動を表示する必要がある.
  • タイムアウト待ち(Time Waiting):Object.wait(1000)メソッド
  • をSynchronizedで呼び出すなど、一定時間システムによって自動的に起動する.
  • ブロック状態(Blocked):取得待ち排他ロック
  • 終了(Terminated):スレッドが終了した状態、スレッドが実行を終了した
  • スレッドSleepとWaitの違い
  • Sleep()はThreadのメソッドであり、WaitはObjectのメソッド
  • である
  • Sleepはコードの任意の部分で実行することができ、WaitはSynchronize修飾の方法またはコードブロックでのみ
  • を実行することができる.
  • SleepはCpuの時間だけを譲ることができて、ロックに対して変化があることはできなくて、Waitは同時にロックとCPU
  • を解放します
    WaitとSleepのDemo
    package com.bdcloud.thread;
    
    import lombok.Synchronized;
    
    import javax.sound.midi.Soundbank;
    
    /**
     *   Sleep Wait  
     */
    public class SleepWaitDemo {
    
        //   
        private static Object lock = new Object();
    
        public static void main(String[] args) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("  A    ,     lock");
                    try {
                        Thread.sleep(20);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (lock) {
                        try {
                            System.out.println("  A    lock");
                            lock.wait(100);
                            System.out.println("  A    ");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
    
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("  B    ,     lock");
                    synchronized (lock){
                        try {
                            System.out.println("  B    ,     lock");
                            Thread.sleep(100);
                            System.out.println("  B    ");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
        }
    }
    
    

    スレッドの戻り値の取得方法
    1つ目は、メインスレッド待ち法を採用する
    package com.bdcloud.thread;
    
    public class CycleWait implements Runnable {
    
        private String value;
        @Override
        public void run() {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            value = "      value";
        }
    
        public static void main(String[] args) {
            CycleWait cycleWait = new CycleWait();
            new Thread(cycleWait).start();
            //    
            while (cycleWait.value == null){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("value ="+cycleWait.value);
        }
    }
    
    

    2つ目は、Threadのjoinメソッドのみで、メインスレッドをブロックしてサブスレッドの実行が終了するのを待つことで、欠点の制御力が足りない
    package com.bdcloud.thread;
    
    public class CycleWait implements Runnable {
    
        private String value;
        @Override
        public void run() {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            value = "      value";
        }
    
        public static void main(String[] args) throws InterruptedException {
            CycleWait cycleWait = new CycleWait();
            Thread thread = new Thread(cycleWait);
            thread.start();
            //              
            thread.join();
            System.out.println("value ="+cycleWait.value);
        }
    }
    
    

    3つ目は、Callableインタフェースによって実現され、FutureTaskまたはスレッドプールによって取得される
    package com.bdcloud.thread;
    
    import java.util.concurrent.Callable;
    
    /***
     *   Callable
     */
    public class MyCallable implements Callable<String> {
        @Override
        public String call() throws Exception {
            System.out.println("task is ready to work!");
            Thread.sleep(100);
            System.out.println("task is Done!");
            return "Hello MyCallable!";
        }
    }
    
    /***
     * Future   Callable    
     */
    package com.bdcloud.thread;
    
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.FutureTask;
    
    public class FutureTaskTest {
        public static void main(String[] args) throws ExecutionException, InterruptedException {
            MyCallable callable = new MyCallable();
            //  FutureTask  Callable     
            FutureTask<String> task = new FutureTask<String>(callable);
            //     
            Thread thread = new Thread(task);
            thread.start();
            while (!task.isDone()){
                System.out.println("task is not finished");
            }
            System.out.println(task.get());
        }
    }
    
    package com.bdcloud.thread;
    
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    
    /***
     *        Callbale   
     */
    public class ThreadPoolDemo {
        public static void main(String[] args) {
            ExecutorService executorService = Executors.newFixedThreadPool(1);
            //                
            Future<String> submit = executorService.submit(new MyCallable());
    
            if (!submit.isDone()){
                System.out.println("       Callable  ");
            }
            try {
                System.out.println(submit.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }finally {
                executorService.shutdown();
            }
        }
    }
    
    

    notifyとnotyfyAllの違い
    まずロックプールと待機プールの概念を導入する
  • ロックプールロックプールは、現在のスレッドがロック待ちの状態である、例えばsynchronizedのメソッドブロックに実行されると、そのロックが別のスレッドによって占有されると、自動的にそのスレッドがロックプールに入れられ、競合CPUリソース実行
  • を待つ.
  • 待機プール待機プールとは、Synchronizedコードブロックでlockを呼び出すことを意味する.wait()メソッドは,スレッドが無限待機状態に入り,CPUリソース
  • と競合しない.
    notifyメソッド:待機プールからスレッドnotifyAllメソッドをランダムに起動します.待機プール内のすべてのスレッドをロックプールに起動します.
    yieldメソッド
    Cpuの現在のスレッドはCpu時間を譲りたいことを暗示しますが、スケジューラは必ずしもこのスレッドを中断するとは限りません.yieldメソッドはロックを解放しません.
    package com.bdcloud.thread;
    
    /***
     * yield  ,      A   yield()       CPU
     */
    public class yieldDemo {
        public static void main(String[] args) {
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < 10; i++) {
                        System.out.println(Thread.currentThread().getName()+i);
                        if (i == 5){
                            //            Cpu
                            Thread.yield();
                        }
                    }
                }
            };
    
            Thread a = new Thread(runnable,"A");
            Thread b = new Thread(runnable,"B");
            a.start();
            b.start();
    
        }
    }
    
    

    interruptメソッド
    以前はスレッドを終了しstopメソッドを呼び出しましたが、このメソッド呼び出しではリソースが解放されずにスレッドを中断する可能性があります.interruptメソッドを使用することをお勧めします.このメソッド呼び出し後、スレッドの中断フラグをtrueとして設定しますが、具体的な中断はスレッドが自主的に決定します.現在のスレッドが待機している場合、例外が放出され、スレッドが終了し、スレッド設定割り込みフラグがtrueの場合、実行は続行されます