天天看點

Next.js+React+Node系統實戰,搞定SSR伺服器渲染

作者:愛學習的小雅2
Next.js+React+Node系統實戰,搞定SSR伺服器渲染

多線程是什麼?為什麼要用多線程?

  介紹多線程之前要介紹線程,介紹線程則離不開程序。

  首先 程序 :是一個正在執行中的程式,每一個程序執行都有一個執行順序,該順序是一個執行路徑,或者叫一個控制單元;

  線程:就是程序中的一個獨立控制單元,線程在控制着程序的執行。一個程序中至少有一個程序。

多線程:一個程序中不隻有一個線程。

  為什麼要用多線程:

    ①、為了更好的利用cpu的資源,如果隻有一個線程,則第二個任務必須等到第一個任務結束後才能進行,如果使用多線程則在主線程執行任務的同時可以執行其他任務,而不需要等待;

    ②、程序之間不能共享資料,線程可以;

    ③、系統建立程序需要為該程序重新配置設定系統資源,建立線程代價比較小;

    ④、Java語言内置了多線程功能支援,簡化了java多線程程式設計。

  

二、線程的生命周期:

建立 :從建立一個線程對象到程式start() 這個線程之間的狀态,都是建立狀态;

就緒 :線程對象調用start()方法後,就處于就緒狀态,等到JVM裡的線程排程器的排程;

運作 :就緒狀态下的線程在擷取CPU資源後就可以執行run(),此時的線程便處于運作狀态,運作狀态的線程可變為就緒、阻塞及死亡三種狀态。

等待/阻塞/睡眠 :在一個線程執行了sleep(睡眠)、suspend(挂起)等方法後會失去所占有的資源,進而進入阻塞狀态,在睡眠結束後可重新進入就緒狀态。

終止 :run()方法完成後或發生其他終止條件時就會切換到終止狀态。

三、建立線程的方法:具體實作代碼詳解請看點選後方連結:多線程擴充一、建立線程的三種方法詳細對比(http://www.cnblogs.com/yjboke/p/8919090.html)

  1、繼承Thread類:

    步驟:①、定義類繼承Thread;

     ②、複寫Thread類中的run方法;

    目的:将自定義代碼存儲在run方法,讓線程運作

     ③、調用線程的start方法:

    該方法有兩步:啟動線程,調用run方法。

  2、實作Runnable接口: 接口應該由那些打算通過某一線程執行其執行個體的類來實作。類必須定義一個稱為run 的無參方法。

    實作步驟: ①、定義類實作Runnable接口

          ②、覆寫Runnable接口中的run方法

             将線程要運作的代碼放在該run方法中。

          ③、通過Thread類建立線程對象。

          ④、将Runnable接口的子類對象作為實際參數傳遞給Thread類的構造函數。

             自定義的run方法所屬的對象是Runnable接口的子類對象。是以要讓線程執行指定對象的run方法就要先明确run方法所屬對象

          ⑤、調用Thread類的start方法開啟線程并調用Runnable接口子類的run方法。

  3、通過Callable和Future建立線程:

    實作步驟:①、建立Callable接口的實作類,并實作call()方法,改方法将作為線程執行體,且具有傳回值。

         ②、建立Callable實作類的執行個體,使用FutrueTask類進行包裝Callable對象,FutureTask對象封裝了Callable對象的call()方法的傳回值

         ③、使用FutureTask對象作為Thread對象啟動新線程。

         ④、調用FutureTask對象的get()方法擷取子線程執行結束後的傳回值。

四、繼承Thread類和實作Runnable接口、實作Callable接口的差別。

    繼承Thread:線程代碼存放在Thread子類run方法中。

        優勢:編寫簡單,可直接用this.getname()擷取目前線程,不必使用Thread.currentThread()方法。

        劣勢:已經繼承了Thread類,無法再繼承其他類。

    實作Runnable:線程代碼存放在接口的子類的run方法中。

        優勢:避免了單繼承的局限性、多個線程可以共享一個target對象,非常适合多線程處理同一份資源的情形。

        劣勢:比較複雜、通路線程必須使用Thread.currentThread()方法、無傳回值。

    實作Callable:

        優勢:有傳回值、避免了單繼承的局限性、多個線程可以共享一個target對象,非常适合多線程處理同一份資源的情形。

        劣勢:比較複雜、通路線程必須使用Thread.currentThread()方法

  建議使用實作接口的方式建立多線程。

五、線程狀态管理

  1、線程睡眠---sleep:

    線程睡眠的原因:線程執行的太快,或需要強制執行到下一個線程。

    線程睡眠的方法(兩個):sleep(long millis)在指定的毫秒數内讓正在執行的線程休眠。

                sleep(long millis,int nanos)在指定的毫秒數加指定的納秒數内讓正在執行的線程休眠。

    線程睡眠的代碼示範:

public class SynTest { public static void main(String[] args) { new Thread(new CountDown(),"倒計時").start(); } }class CountDown implements Runnable{ int time = 10; public void run() { while (true) { if(time>=0){ System.out.println(Thread.currentThread().getName() + ":" + time--); try { Thread.sleep(1000); //睡眠時間為1秒 } catch (InterruptedException e) { e.printStackTrace(); } } } } }

每隔一秒則會列印一次,列印結果為:

倒計時:10倒計時:9倒計時:8倒計時:7倒計時:6倒計時:5倒計時:4倒計時:3倒計時:2倒計時:1倒計時:0

  擴充:Java線程排程是Java多線程的核心,隻有良好的排程,才能充分發揮系統的性能,提高程式的執行效率。但是不管程式員怎麼編寫排程,隻能最大限度的影響線程執行的次序,而不能做到精準控制。因為使用sleep方法之後,線程是進入阻塞狀态的,隻有當睡眠的時間結束,才會重新進入到就緒狀态,而就緒狀态進入到運作狀态,是由系統控制的,我們不可能精準的去幹涉它,是以如果調用Thread.sleep(1000)使得線程睡眠1秒,可能結果會大于1秒。

  2、線程讓步---yield:

     該方法和sleep方法類似,也是Thread類提供的一個靜态方法,可以讓正在執行的線程暫停,但是不會進入阻塞狀态,而是直接進入就緒狀态。相當于隻是将目前線程暫停一下,然後重新進入就緒的線程池中,讓線程排程器重新排程一次。也會出現某個線程調用yield方法後暫停,但之後排程器又将其排程出來重新進入到運作狀态。

public class SynTest { public static void main(String[] args) { yieldDemo ms = new yieldDemo(); Thread t1 = new Thread(ms,"張三吃完還剩"); Thread t2 = new Thread(ms,"李四吃完還剩"); Thread t3 = new Thread(ms,"王五吃完還剩"); t1.start(); t2.start(); t3.start(); } }class yieldDemo implements Runnable{ int count = 20; public void run() { while (true) { if(count>0){ System.out.println(Thread.currentThread().getName() + count-- + "個瓜"); if(count % 2 == 0){ Thread.yield();                  //線程讓步 } } } } }

  sleep和yield的差別:

    ①、sleep方法聲明抛出InterruptedException,調用該方法需要捕獲該異常。yield沒有聲明異常,也無需捕獲。

    ②、sleep方法暫停目前線程後,會進入阻塞狀态,隻有當睡眠時間到了,才會轉入就緒狀态。而yield方法調用後 ,是直接進入就緒狀态。

  3、線程合并---join:

    當B線程執行到了A線程的.join()方法時,B線程就會等待,等A線程都執行完畢,B線程才會執行。

    join可以用來臨時加入線程執行。

    以下為代碼示範:

public static void main(String[] args) throws InterruptedException { yieldDemo ms = new yieldDemo(); Thread t1 = new Thread(ms,"張三吃完還剩"); Thread t2 = new Thread(ms,"李四吃完還剩"); Thread t3 = new Thread(ms,"王五吃完還剩"); t1.start(); t1.join(); t2.start(); t3.start(); System.out.println( "主線程"); }

  4、停止線程:

    原stop方法因有缺陷已經停用了,那麼現在改如何停止線程?現在分享一種,就是讓run方法結束。

    開啟多線程運作,運作的代碼通常是循環結構,隻要控制住循環,就可以讓run方法結束

繼續閱讀