Java中多線程總結

. 建立線程有兩種方式:

1)擴展java.lang.Threadjava

public class ThreadTest extends Thread{ }程序員

2)實現Runnable接口併發

public class ThreadTest implements Runnable{ }this

2. Thread類表明線程類,有兩個最主要的方法:spa

1run() 包含線程運行時所執行的代碼。操作系統

用戶的線程類只須要繼承Thread類,覆蓋Thread類的run()方法便可。在Thread類中的run()方法沒有招聘任何異常,因此Thread子類的run()方法也不能聲明招聘任何異常。線程

2start() 用於啓動線程。orm

3.線程的運行過程:對象

1)主線程與用戶自定義的線程併發運行繼承

2)多個線程共享一個對象的實例變量

3)不要隨便覆蓋Thread類的start()方法,假如必定要覆蓋,就在從新定義的start()方法首語句中調用super.start()方法。

4)一個線程只能被啓動一次

4.線程的狀態轉換:

1)新建狀態

new語句建立的線程對象處於新建狀態,此時它和其餘Java對象同樣,僅僅在堆區中被分配了內存。

2)就緒狀態

當一個線程對象建立後,其餘線程調用它的start()方法,該線程就進入就緒狀態,JVM會爲它建立方法調用棧和程序計數器。處於這個狀態的線程位於可運行池中,等待得到CPU的使用權。

3)運行狀態

處於這個狀態的線程佔用CPU,執行程序代碼。在併發運行環境中,若是計算機只有一個CPU,那麼任什麼時候刻只會有一個線程處於這個狀態。若是計算機有多個CPU,那麼同一時刻可讓幾個線程佔用不一樣的CPU,使它們都處於運行狀態。只有牌就緒狀態的線程纔有機會轉到運行狀態。

4)阻塞狀態

阻塞狀態是指線程由於某些緣由放棄CPU,暫時中止運行。當線程處於阻塞狀態時,JVM不會給線程分配CPU,直到線程從新進入就緒狀態,它纔有機會轉到運行狀態。

阻塞狀態可分爲如下3

1))位於對象等等池中的阻塞狀態:當線程牌運行狀態時,若是執行了某個對象的wait()方法,JVM就會把線程放到這個對象的等待池中。

2))位於對象鎖池中的阻塞狀態:當線程牌運行狀態,試圖得到某個對象的同步鎖時,若是該對象的同步鎖已經被其餘線程佔用,JVM就會把這個線程放到這個對旬的鎖池中。

3))其餘阻塞狀態:當前線程執行了sleep()方法,或者調用了其餘線程的join()方法,或者發出了I/O請求時,就會進入這個狀態。

當一個線程執行System.out.println()或者System.in.read()方法時,就會發出一個I/O請求,該線程放棄CPU,進入阻塞狀態,直到I/O處理完畢,該線程纔會恢復運行。

5)死亡狀態

當線程退出run()方法時,就進入死亡狀態,該線程結束生命週期。線程有多是正常執行完run()方法而退出,也有多是遇到異常而退出。無論線程正常結束仍是異常結束,都不會對其餘其餘線程形成影響。

Thread類的isAlive()方法判斷一個線程是否活着,當線程處於死亡狀態或者新建狀態時,該方法返回false,在其他狀態下,該方法返回true.

5.線程的調度:

有兩種調度方式:分時調度模型和搶佔式調度模型。

分時調度模型是指讓全部線程輪流得到CPU的使用權,而且平均分配每一個線程佔用CPU的時間片。

Java虛擬機採用搶佔式高度模型,是指優先讓可運行池中優先級高的線程佔用CPU,若是可運行池中線程的優先級相同,那麼就隨機選擇一個線程,使其佔用CPU。處於運行狀態的線程會一直運行,直至它不得不放棄CPU

線程的調度不是跨平臺的,它不只取決於JVM,還依賴於操做系統。

6Thread類的setPriority(int)getPriority()方法分別用來設置優先級和讀取優先級。

1MAX_PRIORITY:取值爲10,表示最高優先級

2MIN_PRIORITY:取值爲1,表示最低優先級

3NORM_PRIORITY:取值爲5,表示默認的優先級

若是但願程序能移植到各個操做系統中,應該確保在設置線程的優先級時,只使用MAX_PRIORITYMIN_PRIORITYNORM_PRIORITY這三個優先級。這樣才能保證在不一樣的操做系統中,對一樣優先級的線程採用一樣的調度方式。

7sleep()方法與yield()方法的區別:

1sleep()方法會給其餘線程運行的機會,而不考慮其餘線程的優先級,所以會給較低優先級線程一個運行的機會;yield()方法只會給相同優先級或者更高優先級的線程一個運行的機會。

2)當線程執行了sleep()方法後,將轉到阻塞狀態;當線程執行了yield()方法後,將轉到就緒狀態。

3sleep()方法聲明拋出InterruptedException異常,而yield()方法沒有聲明招聘任何異常。

4sleep()方法比yield()方法具備更好的可移植性。

8.等待其餘線程結束:join()方法

當前運行的線程能夠調用另外一個線程的join()方法,當前運行的線程將轉到阻塞狀態,直至另外一個線程運行結束,它纔會恢復運行(確切的意思是指線程從阻塞狀態轉到就緒狀態)。

9.定時器Timer

Timer timer=new Timer(true);

TimerTask task=new TimerTask(){ }

timer.schedule(task,10,500);//定時器將在10毫秒後開始執行task任務,之後每隔//500毫秒重複執行一次task任務。

timer.schedule(task,10);//只執行一次task任務。

10.同步代碼塊

爲了保證每一個線程能正常執行原子操做,Java引入了同步機制,具體作法是在表明原子操做的程序代碼前加上synchronized標記,這樣的代碼被稱爲同步代碼塊。

有兩種方式加代碼鎖:

1) 直接在方法前加synchronized標記,

public synchronized void add(){... }

2) 在方法內造成synchronized標記的代碼塊

public void add(){synchronized(this){... }}

取得對象鎖:

1) 假如這個鎖已經被其餘線程佔用,JVM就會把這個消費者線程放到Stack對象的鎖池中,消費者線程進入阻塞狀態。在Stack對象的鎖池中可能會有許多等待鎖的線程。等到其餘線程釋放了鎖,JVM會從鎖池中隨機取出一個線程,使這個線程擁有鎖,而且轉到就緒狀態。

2) 假如這個鎖沒有被其餘線程佔用,消費者線程就會得到這把鎖,開始執行同步代碼塊。在通常狀況下,消費者線程只有執行完同步代碼塊,纔會釋放鎖,使得其餘線程可以得到鎖。

釋放對象鎖:

1) 執行完同步代碼塊,就會釋放鎖。

2) 在執行同步代碼塊的過程當中,遇到異常而致使線程終止,鎖也會被釋放。

3) 在執行同步代碼塊的過程當中,執行了鎖所屬對象的wait()方法,這個線程會釋放鎖,進入對象的等待池。

4) 在執行同步代碼塊的過程當中,執行了鎖所屬對象的notify()方法後,JVM會從對象的等待池中隨機選擇一個線程,把它轉到對象的鎖池中。

線程同步的特徵:

1) 若是一個同步代碼塊和非同步代碼塊同時操縱共享資源,仍然會形成對共享資源的競爭。由於當一個線程執行一個對象的同步代碼塊時,其餘線程仍然能夠執行對象的非同步代碼塊。

2) 每個對象都有唯一的同步鎖。

3) 在靜態方法前面也可使用synchronized修飾符。

4) 當一個線程開始執行同步代碼塊時,並不意味着必須以不中斷的方式運行。進入同步代碼塊中的線程也能夠執行Thread.sleep()或者執行Thread.yield()方法,此時它並無釋放鎖,只是把運行機會(即CPU)讓給了其餘的線程。

5) synchronized聲明不會被繼承.

11.死鎖:

當一個線程等等由另外一個線程持有的鎖,然後者正在等待已被第一個線程持有的鎖時,就會發生死鎖。JVM不監測也不試圖避免這種狀況,所以保證不發生死鎖就成了程序員的責任。

相關文章
相關標籤/搜索