1. 程式人生 > >關於java多線程初試

關於java多線程初試

五個 操作系統 滿足 sta strong IT 停止 怎樣 註意

一.什麽是多線程

  在學習多進程之前得先明白兩個概念:

    進程:每個進程都有獨立的代碼和數據空間(進程上下文),進程間的切換會有較大的開銷,一個進程包含1--n個線程,進程是資源分配的最小單位;

    線程:同一類線程共享代碼和數據空間,每個線程有獨立的運行棧和程序計數器(PC),線程切換開銷小,線程是cpu調度的最小單位;

    線程和進程一樣分為五個階段:創建、就緒、運行、阻塞、終止。

    多進程是指操作系統能同時運行多個任務(程序)。

    多線程是指在同一程序中有多個順序流在執行。    

    多線程是多任務的一種特別的形式,但多線程使用了更小的資源開銷。

    這裏定義和線程相關的另一個術語 - 進程:一個進程包括由操作系統分配的內存空間,包含一個或多個線程。一個線程不能獨立的存在,它必須是進程的一部分。一個  進程一直運行,直到所有的非守護線程都結束運行後才能結束。多線程能滿足程序員編寫高效率的程序來達到充分利用 CPU 的目的。

二.怎樣開啟多線程

    在java中要想實現多線程,有兩種手段,一種是繼承Thread類,另外一種是實現Runable接口。

    實現Runable接口:

    實現 Runnable,一個類只需要執行一個方法調用 run(),在創建一個實現 Runnable 接口的類之後,你可以在類中實例化一個線程對象,新線程創建之後,你調用它 的 start() 方法它才會運行。

    繼承Thread類:

    創建一個線程的第二種方法是創建一個新的類,該類繼承 Thread 類,然後創建一個該類的實例。繼承類必須重寫 run() 方法,該方法是新線程的入口點。它也必須 調用 start() 方法才能執行。

三、Thread和Runnable的區別   

    如果一個類繼承Thread,則不適合資源共享。但是如果實現了Runable接口的話,則很容易的實現資源共享。

    總結:

      實現Runnable接口比繼承Thread類所具有的優勢:

      1):適合多個相同的程序代碼的線程去處理同一個資源

      2):可以避免java中的單繼承的限制

      3):增加程序的健壯性,代碼可以被多個線程共享,代碼和數據獨立

      4):線程池只能放入實現Runable或callable類線程,不能直接放入繼承Thread的類

四.線程狀態的轉換

    創建:新創建了一個線程對象;

    就緒狀態(Runnable):線程對象創建後,其他線程調用了該對象的start()方法。該狀態的線程位於可運行線程池中,變得可運行,等待獲 CPU的使用權。

    運行狀態(Running):就緒狀態的線程獲取了CPU,執行程序代碼。

    阻塞狀態(Blocked):阻塞狀態是線程因為某種原因放棄CPU使用權,暫時停止運行。直到線程進入就緒狀態,才有機會轉到運行狀態。阻塞的情況分三種:

     等待阻塞:運行的線程執行wait()方法,JVM會把該線程放入等待池中。(wait會釋放持有的鎖)      同步阻塞:運行的線程在獲取對象的同步鎖時,若該同步鎖被別的線程占用,則JVM會把該線程放入鎖池中。      其他阻塞:運行的線程執行sleep()或join()方法,或者發出了I/O請求時,JVM會把該線程置為阻塞狀態。當sleep()狀態超時、join()等待線程終止或者超時、 或者I/O處理完畢時,線程重新轉入就緒狀態。(註意,sleep是不會釋放持有的鎖)     死亡狀態(Dead):線程執行完了或者因異常退出了run()方法,該線程結束生命周期。 五.常用方法     sleep(long millis): 在指定的毫秒數內讓當前正在執行的線程休眠(暫停執行)      join():指等待t線程終止。      yield():暫停當前正在執行的線程對象,並執行其他線程,在大多數情況下,yield()將導致線程從運行狀態轉到可運行狀態,但有可能沒有效果     sleep()和yield()的區別):sleep()使當前線程進入停滯狀態,所以執行sleep()的線程在指定的時間內肯定不會被執行;yield()只是使當前線程重新回到可執行狀態,所以執行yield()的線程有可能在進入到可執行狀態後馬上又被執行。     sleep()方法(休眠)是線程類(Thread)的靜態方法,調用此方法會讓當前線程暫停執行指定的時間,將執行機會(CPU)讓給其他線程,但是對象的鎖依然保持,因此休眠時間結束後會自動恢復。wait()是Object類的方法,調用對象的wait()方法導致當前線程放棄對象的鎖(線程暫停執行),進入對象的等待池(wait pool),只有調用對象的notify()方法(或notifyAll()方法)時才能喚醒等待池中的線程進入等鎖池(lock pool),如果線程重新獲得對象的鎖就可以進入就緒狀態。     sleep()睡眠時,保持對象鎖,仍然占有該鎖;
    wait()睡眠時,釋放對象鎖。
    notify(): 通知一個線程繼續運行,獲得鎖標記。 六.線程安全    一般理解為線程同步,線程同步的目的是為了保護多個線程反問一個資源時對資源的破壞,線程同步方法是通過鎖來實現,每個對象都有切僅有一個鎖,這個鎖與一個 特定的對象關聯,線程一旦獲取了對象鎖,其他訪問該對象的線程就無法再訪問該對象的其他非同步方法,當多個線程等待一個對象鎖時,沒有獲取到鎖的線程將發生阻 塞,死鎖是線程間相互等待鎖鎖造成的,在實際中發生的概率非常的小。真讓你寫個死鎖程序,不一定好使,呵呵。但是,一旦程序發生死鎖,程序將死掉。
    保持線程同步的方法一般就是加鎖,如synchronized關鍵字。synchronized關鍵字可以作為函數的修飾符,也可作為函數內的語句,也就是平時說的同步方法和同步 語句塊。如果再細的分類,synchronized可作用於instance變量、object reference(對象引用)、static函數和class literals(類名稱字面常量)身上。只要一個線程訪問了其中 的一個synchronized方法,其它線程不能同時訪問這個對象中任何一個synchronized方法。

關於java多線程初試