1)擴展java.lang.Thread類java
public class ThreadTest extends Thread{ }程序員
2)實現Runnable接口併發
public class ThreadTest implements Runnable{ }this
2. Thread類表明線程類,有兩個最主要的方法:spa
1)run() 包含線程運行時所執行的代碼。操作系統
用戶的線程類只須要繼承Thread類,覆蓋Thread類的run()方法便可。在Thread類中的run()方法沒有招聘任何異常,因此Thread子類的run()方法也不能聲明招聘任何異常。線程
2)start() 用於啓動線程。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,還依賴於操做系統。
6.Thread類的setPriority(int)和getPriority()方法分別用來設置優先級和讀取優先級。
1)MAX_PRIORITY:取值爲10,表示最高優先級
2)MIN_PRIORITY:取值爲1,表示最低優先級
3)NORM_PRIORITY:取值爲5,表示默認的優先級
若是但願程序能移植到各個操做系統中,應該確保在設置線程的優先級時,只使用MAX_PRIORITY、MIN_PRIORITY、NORM_PRIORITY這三個優先級。這樣才能保證在不一樣的操做系統中,對一樣優先級的線程採用一樣的調度方式。
7.sleep()方法與yield()方法的區別:
1)sleep()方法會給其餘線程運行的機會,而不考慮其餘線程的優先級,所以會給較低優先級線程一個運行的機會;yield()方法只會給相同優先級或者更高優先級的線程一個運行的機會。
2)當線程執行了sleep()方法後,將轉到阻塞狀態;當線程執行了yield()方法後,將轉到就緒狀態。
3)sleep()方法聲明拋出InterruptedException異常,而yield()方法沒有聲明招聘任何異常。
4)sleep()方法比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不監測也不試圖避免這種狀況,所以保證不發生死鎖就成了程序員的責任。