1. 程式人生 > >Java 多執行緒的理解

Java 多執行緒的理解

Java中的程式是多執行緒的, 一個簡單的程式中包含了兩個執行緒, 即main程式主入口,還有個是gc ,垃圾回收機制的執行緒。

執行緒跟程序的區別:

程序是程式中執行的一個過程,它是一個動態的概念, 程序最少有5種基本狀態,包含了,初始-->執行--->等待-->就緒--> 終止。

執行緒是程序的一部分,一個沒有執行緒的程序以可看成是一個單執行緒,執行緒有時又被稱之為輕量級程序或是輕權程序,也是cpu排程的一個基本單位。

程序的執行過程是線狀的,執行緒只改變cpu的執行過程的改變,而沒有發生程序所擁有的資源變化,程序擁有一個完整的虛擬空間,不依賴於執行緒而獨立存在。 反之,執行緒只是程序的一部分,沒有自己的地址空間,與程序內的其他執行緒共享分配該程序內的所有資源。

執行緒的執行特性: 就緒--->執行--->阻塞

Java中的執行緒

實現:  可以繼承自Thread類 , 或是實現runnable 介面   (推薦使用這種)

           Thread t=new Thread();  t.start();   -->啟動執行緒

join   方法  執行緒A,執行緒B, 執行, 想讓執行緒B執行完後, 在讓執行A, 則可以使用join()

示例中的程式碼執行完thread.join()後,就是將主執行緒最後一個輸出語句放到thread執行完後才執行,因為thread正常情況下永遠執行不完,所以主執行緒永遠不會執行。有一點需要注意的就是threa.join()必須放在thrad.start()後面才會起作用,放在前面是不起作用的。

yield:

作業系統執行的時候是按照cpu的演算法執行各自的執行緒, 當執行緒呼叫yield的時候 可以讓cpu不執行該當前執行緒,也就是將執行緒的執行狀態切換成就緒狀態,但是下一個執行緒要執行哪一個是要根據執行緒排程演算法來確定的,我們並不能確定具體執行那個執行緒,也就是說有可能下一秒當前執行緒又切換成執行狀態。

thread在index 為10的時候讓出了cpu的控制權。

interrupt:

Thread.interrupt 是一個非靜態的方法,它的作用是  “停止”  當前執行緒的執行,為啥要打上雙引號呢,因為只是在特殊的情況下有用,像執行緒呼叫了join,wait,sleep  等可中斷的阻塞方法後,呼叫interrupt  就會丟擲interruptedException 異常。其實,它稱為協作停止。呼叫這個方法,特殊情況外的其他情況下,並不會停止。它傳送一個停止請求,並且由執行緒記錄下來(實際上就是有一個為bool的變數,當為true時就表示有停止執行緒執行請求)。所以說執行緒真正的停止需要我們自己去檢查是否有停止執行緒的請求,當有執行緒停止請求時停用當前執行緒。和它配套使用的有 :

1.public static boolean interrupted()

這個方法是檢查當前執行緒是否有停止請求,需要注意的是這個方法呼叫過後會重置請求標誌位。如果我們第一次呼叫這個方法得到結果是true,那麼這個時候它會重置標誌位,第二次呼叫這個方法得到的結果是false。

2.public boolean isInterrupted()

這個方法是判斷呼叫該方法執行緒是否需要停止,它和靜態的interrupted()有一點很不同的是它不會去重置標誌位。也就是說我們用這個方法查詢第一次是true的話,以後那次查詢都還是true,並不會改變。

例:

像上面這個例子,thread呼叫interrupt停用當前執行緒,但是執行緒並不會停止。而是繼續輸出

如果我們這樣寫

就可以實現了,但是這樣非常耗時,每次都會去檢查是否需要停止。檢查的具體演算法就要看我們具體的需求了。

sleep  , wait  方法對比

sleep 是thread類的靜態方法,不能改變物件的機鎖,讓執行緒進入休眠狀態, 當前執行緒呼叫該方法,讓出cpu時間片, 不會釋放物件鎖, 其他執行緒依然無法訪問該物件。

wait  是Object類的方法, 必須配套這同步方法使用。讓執行緒進入等待狀態,讓出cpu時間片,並釋放物件監視器的所有權(物件鎖),使得其他執行緒能夠訪問,等待其他執行緒通過notify方法來喚醒。

同步方法的三種實現:

1.使用同步程式碼塊 (this, 定義同一個物件就行。Object o=new Object();)

2.同步方法 (定義個方法,使用synchroinzed 修飾就行)

3.互斥鎖(使用Lock 程式碼更靈活)

  互相排斥的鎖, ReetrentLock  lock=new ReetrentLock();   Lock  實現同步

private void  method(){

    Lock.lock(); 鎖

    if(ticket>0{

            ticket--; //模擬火車票售賣,火車票的總票數固定,在不同視窗售賣, 需要保證一張票被一個人購買到,同時總票數要逐漸遞減,保證票數在各大售票視窗一致。使用同步鎖的方法·。保證訂票時,在各大售票視窗請求同一個物件,看誰的手勢快,搶佔該個物件執行,則將該車票售賣給誰,第二位則不能改物件, 進入下一輪的購票。

     try{

       Thread.sleep(millis:5000); //5s

     }catch(InterruptedException e){

         e.printTraceaction();     

     }finally{

      lock.unlock(); //釋放鎖     

     }

    }

}

死鎖產生的情況

一、死鎖原理

      a、根據作業系統中的定義:死鎖是指在一組程序中的各個程序均佔有不會釋放的資源,但因互相申請被其他程序所站用不會釋放的資源而處於的一種永久等待狀態。

二、死鎖的四個必要條件:
     a、互斥條件(Mutual exclusion):資源不能被共享,只能由一個程序使用。
     b、請求與保持條件(Hold and wait):已經得到資源的程序可以再次申請新的資源。
     c、非剝奪條件(No pre-emption):已經分配的資源不能從相應的程序中被強制地剝奪。
     d、迴圈等待條件(Circular wait):系統中若干程序組成環路,該環路中每個程序都在等待相鄰程序正佔用的資源。

三、避免死鎖

     a、按同一順序訪問物件。

     b、避免事務中的使用者互動。

     c、保持事務簡短並處於一個批處理中。

     d、使用較低的隔離級別。

多執行緒產生的死鎖:

  1.過多的同步可能會出現死鎖, 死鎖的操作一般是在程式執行時候才有可能出現

  2.在同一個同步方法中呼叫不同的物件方法。