Java核心API -- 13(線程)

1. 線程相關概念

    進程:一個操作系統中可以同時運行多個任務(程序),每個運行的任務(程序)被稱爲一個進程。

    線程:一個程序同時可能運行多個任務(順序執行流),那麼每個任務(順序執行流)就叫做一個線程。即在進程內部。

    併發:線程是併發運行的。操作系統將時間化分爲若干個片段(時間片),儘可能的均勻分配給每一個任務,被分配時間片後,任務就有機會被cpu所執行。微觀上看,每個任務都是走走停停的。但隨着cpu高效的運行,宏觀上看所有任務都在運行。這種都運行的現象稱之爲併發,但不是絕對意義上的“同時發生”。

    線程調度:線程調度機制會將所有併發任務做統一的調度工作,劃分時間片(可以被cup執行的時間)給每一個任務,時間片儘可能的均勻,但做不到絕對均勻。同樣,被分配時間片後,該任務被cpu執行,但調度的過程中不能保證所有任務都是平均的獲取時間片的次數。只能做到儘可能平均。這兩個都是程序不可控的。

    線程的啓動和停止:void start():想併發操作不要直接調用run方法!而是調用線程的start()方法啓動線程!void stop():不要使用stop()方法來停止線程的運行,這是不安全的操作,想讓線程停止,應該通過run方法的執行完畢來進行自然的結束。


2. 線程的創建方式

    1)繼承自Thread,然後重寫run方法:run方法中應該定義我們需要併發執行的任務邏輯代碼。 


    案例29:

        wKioL1XkHw_Au1k0AAEdp_2fbds855.jpg


    2)實現Runnalbe接口。因爲有了這樣的設計,纔有了線程池。

        Runnable接口:用於定義線程要執行的任務邏輯。我們定一個類實現Runnable接口,這時我們必須重寫run方法,在其中定義我們要執行的邏輯。之後將Runnable交給線程去執行。從而實現了線程與其執行的任務分離開。將任務分別交給不同的線程併發處理,可以使用線程的重載構造方法:Thread(Runnable runnable)。解藕:線程與線程體解藕,即打斷依賴關係。


    案例30:

        wKiom1XkHQuRC71GAAHejxuLVvg919.jpg


    3)線程的創建方式三:使用匿名內部類方式創建線程


    案例31:

        wKiom1XkHYDxqY8DAAGtN4CrDx8701.jpg


3. 線程的生命週期

    線程的生命週期有5種狀態:創建(new)、就緒(runnable)、運行(running)、阻塞(block)、死亡(dead)。

    wKiom1XkHbLCs75hAADsuPCiLa4457.jpg

 

4. 線程的常用方法

    ① static void sleep(times)方法:讓當前線程主動進入Block阻塞狀態,並在time毫秒後回到Runnalbe狀態。 注意事項:使用Thread.sleep()方法阻塞線程時,強制讓我們必須捕獲“中斷異常”。 


    案例32:

        wKioL1XkH_XxbiUlAAErD5_kCWM971.jpg


    ② void interrupt()方法:打斷/喚醒線程。一個線程可以提前喚醒另外一個sleep Block的線程。

        注意事項:方法中定義的類叫局部內部類:局部內部類中,若想引用當前方法的其他局部變量,那麼該變量必須是final的。


    案例33:

        wKioL1XkIBGhtZ1IAALm42J1orE541.jpg


    ③ static void yield():當前線程讓出處理器(離開Running狀態)即放棄當前時間片,主動進入Runnable狀態等待。

    ④ final void setPriority(int):設置線程優先級;優先級越高的線程,理論上獲取cpu的次數就越多。但理想與現實是有差距的……設置線程優先級一定要在線程啓動前設置!


    案例34:

        wKioL1XkIC7wNG47AAItBfgU9Js704.jpg


       

5. wait和notify方法

    這兩個方法不是在線程Thread中定義的方法,這兩個方法定義在Object中。兩個方法的作用是用於協調線程工作的。

        (1) 等待機制與鎖機制密切關聯:wait/notify方法必須與synchronized同時使用,誰調用wait或otify方法,就鎖誰!

        (2) wait()方法:當條將不滿足時,則等待。當條件滿足時,等待該條件的線程將被喚醒。如:瀏覽器顯示一個圖片,displayThread要想顯示圖片,則必須等代下載線程downloadThread將該圖片下載完畢。如果圖片沒有下雜完成,則dialpayThread可以暫停。當downloadThread下載完成後,再通知displayThread可以顯示了,此時displayThread繼續執行。

        (3) notify()方法:隨機通知、喚醒一個在當前對象身上等待的線程。

        (4) notifyAll方法:通知、喚醒所有在當前對象身上等待的線程。


6. 守護線程

    Daemon後臺線程也稱爲守護線程:當前進程中"所有"、"前臺"線程死亡後,後臺線程將被強制死亡(非自然死亡),無論是否還在運行。

    ①守護線程,必須在啓動線程前調用。

    ②main方法也是靠線程運行的,且是一個前臺線程。


    案例35:

        wKiom1XkHjCDw3mxAAJrJu0ibwM526.jpg


7. 線程的併發安全

    多線程在訪問同一個數據時(寫操作),可能會引發不安全操作。

    ① 同步異步:

        同步:同一時刻只能有一個執行,A和B配合工作,步調一致的處理(B得到A的執行結果才能繼續)。如一羣人刷卡上公交車。

        異步:同一時刻能有多個執行,併發,各自幹各自的。如一羣人騎自行車。

    ② synchronized可以修飾方法也可以單獨作爲語句塊存在(同步塊)。作用是限制多線程併發時同時訪問該作用域。

    ③ synchronized修飾方法後,會爲方法上鎖。方法就不是異步的了,而是同步的。鎖的是當前對象。

    ④ synchronized同步塊:分析出只有一段代碼需要上鎖,則使用。效率比直接修飾方法要高。

    ⑤ 線程安全的效率低,如Vector、Hashtable。線程不安全的效率高,如ArrayList、HashMap 。


    案例36:

        wKioL1XkIHSTH7RdAAHnmxfeAyg719.jpg

        wKioL1XkIKewUQQVAAILI56m_NA805.jpg

 

 

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