volatile是一個特殊的修飾符,只有成員變量才能使用它。java
在Java併發程序缺乏同步類的狀況下,多線程對成員變量的操做對其它線程是透明的。安全
volatile變量能夠保證下一個讀取操做會在前一個寫操做以後發生。多線程
首先,volatile 變量和 atomic 變量看起來很像,但功能卻不同。架構
Volatile變量能夠確保先行關係,即寫操做會發生在後續的讀操做以前, 但它並不能保證原子性。例如用volatile修飾count變量那麼 count++ 操做就不是原子性的。併發
而AtomicInteger類提供的atomic方法可讓這種操做具備原子性如getAndIncrement()方法會原子性的進行增量操做把當前值加一,其它數據類型和引用變量也能夠進行類似操做。dom
同步集合與併發集合都爲多線程和併發提供了合適的線程安全的集合,不過併發集合的可擴展性更高。異步
Java5介紹了併發集合像ConcurrentHashMap,不只提供線程安全還用鎖分離和內部分區等現代技術提升了可擴展性。分佈式
Vector 是用同步方法來實現線程安全的函數
通常而言,讀寫鎖是用來提高併發程序性能的鎖分離技術的成果。高併發
Java中的ReadWriteLock是Java 5 中新增的一個接口,一個ReadWriteLock維護一對關聯的鎖,一個用於只讀操做一個用於寫。在沒有寫線程的狀況下一個讀鎖可能會同時被多個讀線程持有。寫鎖是獨佔的,你可使用JDK中的ReentrantReadWriteLock來實現這個規則,它最多支持65535個寫鎖和65535個讀鎖。
在Java併發程序中FutureTask表示一個能夠取消的異步運算。
它有啓動和取消運算、查詢運算是否完成和取回運算結果等方法。只有當運算完成的時候結果才能取回,若是運算還沒有完成get方法將會阻塞。一個FutureTask對象能夠對調用了Callable和Runnable的對象進行包裝,因爲FutureTask也是調用了Runnable接口因此它能夠提交給Executor來執行。
ThreadLocal是Java裏一種特殊的變量。
每一個線程都有一個ThreadLocal就是每一個線程都擁有了本身獨立的一個變量,競爭條件被完全消除了。它是爲建立代價高昂的對象獲取線程安全的好方法,好比你能夠用ThreadLocal讓SimpleDateFormat變成線程安全的,由於那個類建立代價高昂且每次調用都須要建立不一樣的實例因此不值得在局部範圍使用它,若是爲每一個線程提供一個本身獨有的變量拷貝,將大大提升效率。
首先,經過複用減小了代價高昂的對象的建立個數。 其次,你在沒有使用高代價的同步或者不變性的狀況下得到了線程安全。
線程局部變量的另外一個不錯的例子是ThreadLocalRandom類,它在多線程環境中減小了建立代價高昂的Random對象的個數。
線程轉儲是一個JVM活動線程的列表,它對於分析系統瓶頸和死鎖很是有用。
有不少方法能夠獲取線程轉儲——使用Profiler,Kill-3命令,jstack工具等等。有的更喜歡jstack工具,由於它容易使用而且是JDK自帶的。因爲它是一個基於終端的工具,因此能夠編寫一些腳本去定時的產生線程轉儲以待分析。
若是你使用的LinkedBlockingQueue,也就是無界隊列的話,不要緊,繼續添加任務到阻塞隊列中等待執行,由於LinkedBlockingQueue能夠近乎認爲是一個無窮大的隊列,能夠無限存聽任務;
若是你使用的是有界隊列比方說ArrayBlockingQueue的話,任務首先會被添加到ArrayBlockingQueue中,ArrayBlockingQueue滿了,則會使用拒絕策略RejectedExecutionHandler處理滿了的任務,默認是AbortPolicy。
當線程間是能夠共享資源時,線程間通訊是協調它們的重要的手段。
Object類中wait()notify()notifyAll()方法能夠用於線程間通訊關於資源的鎖的狀態。
Thread類提供了一個holdsLock(Object obj)方法,當且僅當對象obj的監視器被某條線程持有的時候,纔會返回true.注意這是一個static方法,這意味着」某條線程」指的是當前線程。
死鎖是指兩個或兩個以上的進程在執行過程當中,因爭奪資源而形成的一種互相等待的現象,若無外力做用,它們都將沒法推動下去。
一、自旋鎖 二、自旋鎖的其餘種類 三、阻塞鎖 四、可重入鎖 五、讀寫鎖 六、互斥鎖 七、悲觀鎖 八、樂觀鎖 九、公平鎖 十、非公平鎖 十一、偏向鎖 十二、對象鎖 1三、線程鎖 1四、鎖粗化 1五、輕量級鎖 1六、鎖消除 1七、鎖膨脹 1八、信號量
產生死鎖的四個必要條件:
打破產生死鎖的四個必要條件中的一個或幾個,保證系統不會進入死鎖狀態。
活鎖和死鎖相似,不一樣之處在於處於活鎖的線程或進程的狀態是不斷改變的,活鎖能夠認爲是一種特殊的飢餓。
一個現實的活鎖例子是兩我的在狹小的走廊碰到,兩我的都試着避讓對方好讓彼此經過,可是由於避讓的方向都同樣致使最後誰都不能經過走廊。
簡單的說就是,活鎖和死鎖的主要區別是前者進程的狀態能夠改變可是卻不能繼續執行。
飢餓是指系統不能保證某個進程的等待時間上界,從而使該進程長時間等待,當等待時間給進程推動和響應帶來明顯影響時,稱發生了進程飢餓。當飢餓到必定程度的進程所賦予的任務即便完成也再也不具備實際意義時稱該進程被餓死。
死鎖是指在多道程序系統中,一組進程中的每個進程都無限期等待被該組進程中的另外一個進程所佔有且永遠不會釋放的資源。
相同點:兩者都是因爲競爭資源而引發的。
不一樣點:
悲觀鎖:假定會發生併發衝突,屏蔽一切可能違反數據完整性的操做。 樂觀鎖:假設不會發生併發衝突,只在提交操做時檢查是否違反數據完整性。樂觀鎖不能解決髒讀的問題。
對象鎖是指Java爲臨界區synchronized(Object)語句指定的對象進行加鎖,對象鎖是獨佔排他鎖。
對於對象鎖,是針對一個對象的,它只在該對象的某個內存位置聲明一個標誌位標識該對象是否擁有鎖,因此它只會鎖住當前的對象。通常一個對象鎖是對一個非靜態成員變量進行syncronized修飾,或者對一個非靜態方法進行syncronized修飾。對於對象鎖,不一樣對象訪問同一個被syncronized修飾的方法的時候不會阻塞住。
在java.lang.Thread中有一個方法叫holdsLock(),它返回true若是當且僅當當前線程擁有某個具體對象的鎖。
Java在過去很長一段時間只能經過synchronized關鍵字來實現互斥,它有一些缺點。好比你不能擴展鎖以外的方法或者塊邊界,嘗試獲取鎖時不能中途取消等。Java 5 經過Lock接口提供了更復雜的控制來解決這些問題。 ReentrantLock 類實現了 Lock,它擁有與 synchronized 相同的併發性和內存語義且它還具備可擴展性。
可重入鎖,也叫作遞歸鎖,指的是同一線程 外層函數得到鎖以後 ,內層遞歸函數仍然有獲取該鎖的代碼,但不受影響。
在Java環境下 ReentrantLock 和synchronized 都是可重入鎖
CAS,全稱爲Compare and Swap,即比較-替換。假設有三個操做數:內存值V、舊的預期值A、要修改的值B,當且僅當預期值A和內存值V相同時,纔會將內存值修改成B並返回true,不然什麼都不作並返回false。固然CAS必定要volatile變量配合,這樣才能保證每次拿到的變量是主內存中最新的那個值,不然舊的預期值A對某條線程來講,永遠是一個不會變的值A,只要某次CAS操做失敗,永遠都不可能成功
原文:Java架構筆記
免費Java高級資料須要本身領取,涵蓋了Java、Redis、MongoDB、MySQL、Zookeeper、Spring Cloud、Dubbo高併發分佈式等教程,一共30G。
傳送門: https://mp.weixin.qq.com/s/JzddfH-7yNudmkjT0IRL8Q