---恢復內容開始---java
1.線程與進程數組
一個程序至少須要一個線程,一個進程至少須要一個線程 線程->進程->程序安全
線程是程序執行流的最小單位,進程是系統進行資源分配和調度的一個獨立單位。多線程
①start()方法:開始執行該線程app
②stop()方法:強制結束該線程jvm
③join()方法 :等待該線程結束性能
④sleep()方法:該線程進入等待學習
⑤run()方法 :直接執行該線程的run方法(線程調用start()也會執行run方法,區別是一個是由線程調度運行run 方法,一個是直接調用線程中的run方法)優化
注意:wait()和notify()是object中的方法,分別表示線程掛起和線程恢復spa
wait()與sleep()的區別:wait()會釋放對象鎖,sleep()不會釋放對象鎖
線程共有5大狀態
①新建狀態:新建線程對象,並無調用start以前
②就緒狀態:調用start方法以後就進入就緒狀態,另外線程在睡眠和掛起中恢復的時候也會進入就緒狀態
③運行狀態:線程被設置爲當前線程開始執行run方法
④阻塞狀態:線程被暫停。好比調用sleep方法後
⑤死亡狀態:線程執行結束
①可重入鎖:在執行對象中全部同步方法不用再次得到鎖
②可中斷鎖:在等待獲取鎖過程當中可中斷
③公平鎖:按等待獲取鎖的線程的等待時間進行獲取,等待時間長的具備優先獲取鎖的權力
④讀寫鎖:對資源讀取和寫入的時候拆分爲2部分處理,讀的時候能夠多線程一塊兒讀,寫的時候必須同步的寫
java中每一個對象均可做爲鎖,鎖有四種級別,按照量級從輕到重分爲:無鎖,偏向鎖,輕量級鎖,重量級鎖。每一個對象一開始都是無鎖的,隨着線程間爭奪鎖,越激烈,鎖的級別越高,而且鎖只能升級不能降級。
鎖的實現機制與java對象頭息息相關,鎖的全部信息都記錄在java的對象頭中,用2字(32位JVM中1字=32bit)存儲對象頭,若是是數組類型使用3字存儲(還須要存儲數組長度),對象頭中記錄了hash值,GC年齡,鎖的狀態,線程擁有者,類元數據的指針
類別 | synchronized | lock |
存在層次 | Java的關鍵字,在jvm層面上 | 是一個類 |
鎖的釋放 | 1.以獲取鎖的線程執行同步代碼,釋放鎖 2.線程執行發生異常,jvm會讓線程釋放鎖 |
在finally中必須釋放鎖,否則容易形成線程死鎖 |
鎖的獲取 | 假設A線程得到鎖,B線程等待,若是A線程阻塞,B線程會一直等待 | 分狀況而定,Lock有多個鎖獲取的方式,能夠嘗試得到鎖,線程能夠不用一直等待 |
鎖狀態 | 沒法判斷 | 能夠判斷 |
鎖類型 | 可重入,不可中斷,非公平 | 可重入,可判斷,可公平(二者皆可) |
性能 | 少許同步 | 大量同步 |
Lock接口的方法
①lock() :獲取鎖 若是鎖被暫用則一直等待
②unlock():釋放鎖
③trylock():返回類型是boolean,若是獲取鎖的時候鎖被佔用就返回false,不然返回true
④tryLock(long time,TimeUnit unit):比起tryLock()就是給了一個時間期限,保證等待參數時間
⑤lockInterruptibly():用該鎖的得到方式,若是線程在獲取鎖的階段進入了等待,那麼能夠中斷此線程,先去作別的事
synchronized:查看源碼能夠知道synchronized映射成字節碼指令就是增長來拉個指令:monitorenter和monitorexit.當一條線程進行執行遇到monitorenter指令的時候,他會去嘗試得到鎖,若是得到鎖那麼鎖計數+1,由於它是一個可重入鎖,因此須要用這個鎖計數判斷鎖的狀況,若是沒有得到鎖,那麼阻塞,當它遇到monitorexit的時候,鎖計數-1,當計數器爲0,就會釋放鎖。
synchronized鎖釋放有兩種機制,一種是執行完釋放,另一種就是發送異常,虛擬機釋放,上圖的第二個monitorexit就是發生異常執行的流程,在13行的goto指令,意思是若是正常運行結束會跳轉到19行執行
lock:synchronized是一種悲觀鎖,每次都把本身關起來作事,怕被搶而lock底層是CAS樂觀鎖的體現,無所謂外界,若是被搶了,就從新去拿,很樂觀,底層主要靠volatile和CAS實現的
注意:儘量去使用synchronized而不要去使用lock
在jdk1.6~jdk1.7的時候,也就是synchronized1六、7年的時候,作了不少優化
synchronized能夠保證方法或者代碼塊在運行時同一時刻只有一個線程能進入臨界區,同時保證共享變量對其餘線程的可見性
JDK1.6以前Synchronized是一個重量級鎖,是經過對象內部的一個叫作監視器鎖(monitor)來實現的,可是監視器本質又是依賴於底層的操做系統的Mutex Lock來實現的,而操做系統實現線程之間的切換這就須要從用戶態轉換到核心態
優化:
①線程自旋和適應性自旋
java線程實際上是映射在內核之上的,線程的掛起和恢復會極大的影響開銷,而且jdk官方人員發現,不少線程在等待鎖的時候,在很短的一段時間就得到了鎖,因此他們在線程等待的時候,並不須要把線程掛起,而是讓他無目的循環,通常設置10次,這樣就避免了線程切換的開銷,極大的提高了性能。而自適應自旋,是賦予自旋一種學習能力,它並不固定自旋10次一下。他能夠根據它前面線程的自旋狀況,從而調整它的自旋。甚至是不通過自旋而直接掛起
②鎖消除
鎖消除就是把沒必要要的同步在編譯階段進行移除,這裏的鎖消除並不必定指你寫的代碼的鎖消除。
好比stringBuffer是一個安全的類,它在執行一個簡單的append方法拼接字符串,append方法都會同步,但分析能夠知道這並不存在線程安全問題,這時就會把這個同步鎖消除
③鎖粗化
在用synchronized時,都講究避免大開銷,儘管同步代碼塊要小,爲何還要加粗呢。哪stringBuffer拼接字符串來講,每個append都須要同步一次,那就能夠把鎖粗化到第一個和最後一個append
④輕量級鎖
⑤偏向鎖
---恢復內容結束---