java基礎之多線程

多線程:
    概述: 進程有多條執行路徑, 合成爲: 多線程.
        進程: 可執行程序(文件), 例如: .exe
            //可以把進程理解爲一輛車.
        線程: 進程的執行路徑(執行單元)
            //可以把線程理解爲: 是馬路

        記憶:
            1. 一臺電腦上可以有多個進程, 這些進程之間的數據是相互隔離的.
                //例如: qq.exe,  飛秋.exe
            2. 一個進程可以有多條線程, 這些線程可以共享該進程的數據.
                //例如: 往QQ羣共享放一個文件, 該羣中的所有的用戶都可以下載.

    多線程並行和併發的區別是什麼:
        並行: 兩個(多個)線程同時執行.   //前提: 需要多核CPU

        併發: 
            兩個(多個)線程同時請求執行, 但是CPU同一瞬間只能執行一個線程,
            於是就安排這些線程交替執行, 因爲時間間隔非常短, 我們看起來好像是同時執行的, 其實不是.

    多線程的實現方式:
        方式一: 繼承Thread類.
            步驟:
                1) 定義一個類(MyThread), 繼承Thread類.
                2) 重寫Thread#run().
                   //重寫Thread類中的run()方法.
                3) 把要執行的代碼放入run()方法中.
                4) 在測試類中,創建線程對象.
                5) 開啓線程.        //start()

                注意事項:
                    A: 如果調用run()方法, 只是普通的方法調用.
                    B: 開啓線程必須調用start()方法, 該方法會自動去調用run()方法.            
                    C: 同一線程不能重複開啓, 否則會報: IllegalThreadStateException異常.

        方式二: 實現Runnable接口.
            步驟:
                1) 定義一個類(MyRunnable), 實現Runnable接口.
                2) 重寫Runnable#run().
                3) 把要執行的代碼放入run()方法中.
                4) 在測試類中, 創建Runnable接口的子類對象, 
                    MyRunnable mr = new MyRunnable();
                   並將其作爲參數傳入Thread類的構造, 創建線程對象.
                    Thread th = new Thread(mr);
                5) 開啓線程.        //start()

        方式三: 結合線程池使用(實現Callable接口).         //暫時瞭解即可.

    多線程的執行特點是什麼:
        隨機性, 延遲性.
        因爲CPU在做着高效的切換.

    多線程案例: 模擬賣票.
        //需求: 四個窗口, 賣100張票.
        出現的問題:
            出現負數:if條件
            出現重複值:ticket--

        解決方案:
            採用 同步代碼塊解決.

    Thread類中的成員:
        構造方法:
            public Thread();
            public Thread(String name);
            public Thread(Runnable target);
            public Thread(Runnable target,String name);

        成員方法:
            run();  //裏邊定義的是線程要執行的代碼, 該方法會自動被start()方法調用.
            start();  //開啓線程, 會自動調用run().
            getName();
            setName();
            sleep();  //休眠線程, 單位是: 毫秒.
            currentThread();  //獲取當前正在執行的線程對象(的引用).

    同步:
        概述/作用:
            多線程(環境) 併發 操作同一數據, 有可能引發安全問題, 就需要用到同步解決.
        分類:
            同步代碼塊:
                格式:
                    synchronized(鎖對象) {
                        //要加鎖的代碼
                    }
                鎖對象:
                    1) 同步代碼塊的鎖對象可以是任意類型的對象.
                    2) 必須使用同一把鎖, 否則可能出現鎖不住的情況.

            同步方法:
                靜態方法:
                    鎖對象: 該類的字節碼文件對象.
                非靜態方法:
                    鎖對象: this


    多線程的難點(一般只在面試的時候用, 工作中基本不用)
        死鎖:
            死鎖是指兩個或兩個以上的進程在執行過程中,由於競爭資源或者由於彼此通信而造成的
            一種阻塞的現象,若無外力作用,它們都將無法推進下去。

        多線程的生命週期:
            新建, 就緒, 運行(有可能發生阻塞和等待), 死亡.

    擴展的知識:
        1) 匿名內部類:       //本質是一個對象.          //記憶&掌握
            內部類:
                概述: 類裏邊還有一個類, 裏邊那個類叫內部類, 外邊那個類叫外部類.
                分類:
                    成員內部類:  定義在成員位置的內部類.
                    局部內部類:  定義在局部位置的內部類.

            概述:
                就是沒有名字的 局部內部類.

            格式:
                new 類名或者接口名(){
                    //重寫類或者接口中 所有的 抽象方法;
                };

            本質:
                專業版: 就是一個繼承了類或者實現了接口的 匿名的子類對象.
                大白話: 匿名內部類不是類, 而是子類對象.

            匿名內部類在實際開發中的應用:
                1) 當對 對象方法(成員方法) 僅調用一次的時候.
                2) 可以作爲方法的實參進行傳遞.

            個人建議:
                當接口中或者抽象類中的 抽象方法僅有一個的時候, 就可以 考慮使用匿名內部類.

        2) 實現Runnable接口的原理.     //多態.
            背景:
                多線程的第一種實現方式是: 繼承Thread類, 因爲我們自定義的類(MyThread)是Thread類的子類,
                所以MyThread類的對象調用start()方法的時候, 自動調用MyThread#run(), 這個我們可以理解, 

                但是MyRunnable類是實現了Runnable接口, 而Runnable接口的run()方法和Thread#start()沒有關係, 
                問: 爲什麼Thread#start(), 會自動調用Runnable接口的子類(MyRunnable)中的 run()方法呢?

            簡化版的源碼:
                測試類中的代碼
                public static void main(String[] args) {
                    MyRunnable mr = new MyRunnable();
                    Thread th = new Thread(mr);
                    th.start(); //問: 爲什麼會自動調用 MyRunnable#run();
                }

                public class Thread {
                    private Runnable target;            //new MyRunnable();
                    public Thread(Runnable target) {    //new MyRunnable();
                        this.target = target;
                    }

                    public void run() {
                        if(target != null) {
                            target.run();               //new MyRunnable().run();
                        }
                    }

                }

         從Eclipse貼過來的源碼:

            public class Thread {
                 private Runnable target;
                 public Thread(Runnable target) {
                    init(null, target, "Thread-" + nextThreadNum(), 0);
                }

                private void init(ThreadGroup g, Runnable target, String name,
                  long stackSize) {
                    init(g, target, name, stackSize, null);
                }

                private void init(ThreadGroup g, Runnable target, String name,
                  long stackSize, AccessControlContext acc) {
                    this.target = target;
                }

                 @Override
                public void run() {
                    if (target != null) {
                        target.run();
                    }
                }
            }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章