本文及後續相關文章梳理一下關於多線程和同步鎖的知識,平時只是應用層面的瞭解,因爲最近面試老是問一些原理性的知識,雖然說比較反感這種理論派,可是爲了生計也必須掌握一番。(PS:並非說掌握原理很差,可是封裝就是爲了更好的應用,我的感受不必爲了學習而學習,比較傾向於行動派,能將原理應用到實際纔算參透,本文也僅僅是背書而已)
進程
:進程就是一段程序的執行過程,指在系統中能獨立運行並做爲資源分配的基本單位,它是由一組機器指令、數據和堆棧等組成的,是一個能獨立運行的活動實體。線程
:線程是進程中的一個實體,做爲系統調度和分派的基本單位。Linux下的線程看做輕量級進程。線程和進程同樣分爲五個階段:建立、就緒、運行、阻塞、終止
多進程是指操做系統能同時運行多個任務(程序)
多線程是指在同一程序中有多個順序流在執行
- 實現Runnable接口java
Public class A implements Runnable { public void run () { // 必須實現run方法 // 線程執行的業務代碼 } }
上面實現了Runnable
接口並經過run
方法包裝了須要經過線程執行的代碼
- 運行線程
經過實現了Runnable
接口的類的實例
建立線程對象(Thread)
來運行線程,經常使用的Thread
構造方法:程序員
Thread(Runnable threadOb,String threadName);
其中threadOb
是一個實現Runnable
接口的類的實例
,threadName
指定線程的名字
調用線程類中的start()
方法運行線程 new Thread(threadOb,threadName).start();
(可建立多個線程對象
運行同一個Runnable
接口實例的run
方法,實現資源共享
)面試
PS:start()
方法的調用後並非當即執行多線程代碼,而是使得該線程變爲可運行態(Runnable)
,等待CPU分配調度執行
- 繼承Thread類安全
public class A extends Thread { @Override public void run() { // 重寫run方法 // 線程執行的業務代碼 } }
上面繼承了Runnable
接口並經過重寫run
方法包裝了須要經過線程執行的代碼,經過源碼能夠看到Thread
類也是實現了Runnable
接口的,因此本質上和上一種方式無太大區別,不一樣的是Thread類不適合共享資源
線程實現
- 運行線程多線程
一樣是調用線程類中的start()
方法運行線程,此時線程類爲繼承Thread的類ide
- 實現Callable接口學習
public class A implements Callable<T> { @Override public T call() throws Exception // 實現call()方法 { // 線程執行的業務代碼 } }
建立Callable
接口的實現類(經過泛型制定線程執行結束後的返回值類型)
,並實現call()
方法,該call()
方法將做爲線程執行體,而且有返回值
(返回值類型爲Callable
接口泛型制定的類型)
- 使用FutureTask
類來包裝Callable對象
操作系統
FutureTask<T> ft = new FutureTask<>(callableObj);
其中callableObj
爲Callable
實現類的實例,使用FutureTask
類來包裝Callable
對象,該FutureTask對象
封裝了該Callable對象
的call()
方法的返回值
- 運行線程線程
經過FutureTask
類的實例建立
線程對象(Thread)來運行線程,此時應用的
Thread`構造方法:code
Thread(FutureTask futureObj,String threadName);
其中futureObj
是一個FutureTask
類的實例
,threadName
指定線程的名字
調用線程類中的start()
方法運行線程 new Thread(threadOb,threadName).start();
調用FutureTask
對象的get()
方法來得到子線程執行結束後的返回值
start()
方法重複調用,會出現java.lang.IllegalThreadStateException
異常直接繼承Thread類和實現接口方式建立線程的區別
Runable
或callable
類線程,不能直接放入繼承Thread
的類main線程
和垃圾收集線程
sleep(long millis)
: 在指定的毫秒數內讓當前正在執行的線程休眠(暫停執行),可用TimeUnit.MILLISECONDS.sleep
方法替換join()
: 等待調用join()的線程終止
使用方式
`Thread t = new AThread(); t.start(); t.join();`
join()的做用是將線程加入到
當前線程
中,只有執行完join()調用線程才能執行後面的代碼
yield()
: 暫停當前正在執行的線程對象,並執行其餘線程
使用場景yield()
應該作的是讓當前運行線程回到可運行狀態,以容許具備相同優先級
的其餘線程得到運行機會。所以,使用yield()
的目的是讓相同優先級的線程之間能適當的輪轉執行。可是,實際中沒法保證yield()達到讓步目的
,由於讓步的線程還有可能被線程調度程序再次選中
PS:yield()
方法執行時,當前線程仍處在可運行狀態,因此,不可能讓出較低優先級的線程些時得到CPU
佔有權。在一個運行系統中,若是較高優先級的線程沒有調用sleep方法
,又沒有受到I\O 阻塞
,那麼,較低優先級線程只能等待全部較高優先級的線程運行結束,纔有機會運行
setPriority()
: 更改線程的優先級,優先級高的線程會得到較多的運行機會
優先級靜態常量MIN_PRIORITY
=1,NORM_PRIORITY
=5,MAX_PRIORITY
=10
使用方式
Thread t1 = new Thread("t1"); Thread t2 = new Thread("t2"); t1.setPriority(Thread.MAX_PRIORITY); t2.setPriority(Thread.MIN_PRIORITY);
interrupt()
: 將線程對象的中斷標識設成true
使用說明
interrupt
方法將該線程的標識位設爲true;能夠在別的線程中調用,也能夠在本身的線程中調用使用方式
設置中斷監聽(另外一種方式)
Thread t1 = new Thread( new Runnable(){ public void run(){ // 若未發生中斷,就正常執行任務 while(!Thread.currentThread.isInterrupted()){ // 正常任務代碼…… } // 中斷的處理代碼…… doSomething(); } } ).start();
觸發中斷
t1.interrupt();
wait()
: 主動釋放對象鎖,同時本線程休眠,直到有其它線程調用對象的notify()
喚醒該線程,從新獲取對象鎖並執行(wait()
方法屬於Object
中的方法,並不屬於Thread
類)notify()
: 喚醒調用notify()對象的線程,notify()調用後,並非立刻就釋放對象鎖的,而是在相應的synchronized(){}語句塊執行結束,自動釋放鎖後,JVM會在wait()對象鎖的線程中隨機選取一線程,賦予其對象鎖,喚醒線程,繼續執行1.sleep()
和yield()
的區別
睡眼
一段時間,進入不可運行狀態,這段時間的長短是由程序設定的,yield方法使當前線程讓出CPU佔有權
,但讓出的時間是不可設定的。實際上,yield()方法對應了以下操做:先檢測當前是否有相同優先級的線程處於同可運行狀態,若有,則把CPU的佔有權交給此線程,不然,繼續運行原來的線程。因此yield()方法稱爲'退讓',它把運行機會讓給了同等優先級的其餘線程2.wait()
和sleep()
區別
共同點:
interrupt()
方法 打斷線程的暫停狀態,從而使線程馬上拋出InterruptedException
須要注意的是,InterruptedException
是線程本身從內部拋出的,並非interrupt()
方法拋出的。對某一線程調用interrupt()
時,若是該線程正在執行普通的代碼,那麼該線程根本就不會拋出InterruptedException
。可是,一旦該線程進入到wait()
/sleep()
/join()
後,就會馬上拋出InterruptedException
不一樣點:
簡單來講:
sleep()方法
阻塞當前線程
),讓出CPU的使用、目的是不讓當前線程獨自霸佔該進程所獲的CPU資源,以留必定時間給其餘線程執行的機會;Thread
類的Static
的方法;所以他不能改變對象的機鎖,因此當在一個Synchronized塊中調用Sleep()方法是,線程雖然休眠了,可是對象的機鎖並無被釋放,其餘線程沒法訪問這個對象(即便休眠也持有對象鎖
)wait()方法
Object
類裏的方法;當一個線程執行到wait()方法時,它就進入到一個和該對象相關的等待池中,同時失去(釋放)了對象的機鎖(暫時失去機鎖,wait(long timeout)超時時間到後還須要返還對象鎖);其餘線程能夠訪問;notify
或者notifyAlll
或者指定睡眠時間來喚醒當前等待池中的線程。synchronized block
中,不然會在程序runtime
時扔出java.lang.IllegalMonitorStateException
異常。