1. 程式人生 > >JAVA-CONCURRENCY IN PRACTICE章節一翻譯

JAVA-CONCURRENCY IN PRACTICE章節一翻譯

參考了很多童老師團隊的翻譯,自己也看英文對照,有修改

章節一:

寫一個正確的程式,難,寫一個正確的併發程式,難上加難。相比於非併發程式(個人理解是單執行緒那種的),併發程式裡有更多容易產生錯誤的地方。那麼為啥我們還要這麼費勁研究併發呢?因為執行緒Thread是java程式語言裡誰都躲不掉的功能啊,而且Threads還能通過把複雜非同步程式碼轉換成直線式程式(這裡應該是指換成併發執行的程式碼塊?),簡化複雜系統的開發。此外,執行緒Threads也是能夠挖掘發揮多處理器系統(多核)計算能力最簡單的方法。隨著CPU的增加更有效利用併發肯定會變得越來越重要。

1.1併發發展簡史

 在計算機歷史中的遠古時代,電腦都沒有作業系統;他們從頭到尾執行一個單個的程式,並且這個程式能直接接觸到計算機機器上所有資源。這就造成了以下結果:在暴露所有一切給你的機器上去寫個能執行的程式很困難,考慮到昂貴稀缺的電腦資源,一次跑一個單個程式也是效率很低的事情。

 作業系統發展起來後,允許不止一個程式在程序中即刻獨立的執行:作業系統為他們分配諸如儲存、檔案控制代碼、安全憑證等資源,保證他們獨立的執行。如果有需要的話,程序也能夠通過一種粗粒度的交流機制,和其他程序進行交流,像sockets套接字、訊號處理程式、共享儲存、訊號燈和檔案。

幾種積極的激勵因素促使作業系統不斷髮展,來允許更多的程式同時去執行:

資源利用率--程式有時候不得不等待諸如輸入輸出的額外操作,在等待期間不能做什麼有用的工作。這種等待的時間如果能用來執行別的程式當然是更有效率的。

公平性--多使用者或者多程式可能對計算機資源有相同的要求。相比於讓一個程式跑完再讓另一個程式開始執行,通過更細粒度的時間切片去劃分誰在哪個極微小時間單位內佔有電腦資源,這樣顯然效率更高。

方便性--與寫一個單獨的程式跑所有的任務相比,寫幾個程式,然後每個程式執行一個單獨的任務並在必要的時候協調呼叫,顯然要簡單或者說更值得去這樣做。

 在早期的分時系統中,每個程序都是一臺虛擬的馮諾依曼計算機;每個程序都有一個儲存空間,儲存著所有的指令和資料。這些順序執行指令根據機器語言的語義所寫,指令通過在作業系統中操作一套I/O原語(原函式)和外界進行互動。對於每一個被執行的指令,都有明確定義的“下一條指令”,並且控制流程會根據指令集合定義的規則跑完程式。今天近乎所有的被廣泛應用的程式語言都遵循這個程式順序執行模型,語言規範裡清楚定義了在給出的任務執行後“下一步去幹啥”。

 程式順序執行模型是直觀自然的,它就像是人類工作的方式:一段時間內按著順序走就幹一個事------大多數情況下。比如起床,穿浴衣,下樓,喝茶去。在程式語言中,這些真實世界的每一個活動就是程式裡順序執行行為的抽象物。比如說開啟櫥櫃,選擇一種品牌的茶,估計一下到多少茶葉,看下茶壺裡水夠不夠,不夠添點,把火爐開啟,等茶水煮開了喝等等。像這最後一步操作--等茶水煮開的過程中---就涉及到了非同步。當水在加熱時,你可以選擇去幹啥---傻了吧唧等著或者在這段時間內幹別的事,比如開始烤麵包(另一個非同步任務)或者看看報紙,當然都要有一點注意力給你的茶壺,有需要的話趕緊回來弄。茶壺和麵包機的製造商知道他們的產品總會在一些非同步行為情況下被使用,所以他們設計產品的時候讓它能夠在完成任務的時候發出聲音訊號。找到同步和非同步的平衡點是一個高效的人的特點,對程式來說也一樣。

同樣的關注(資源利用率,公平性,方便性等方面)促進了程序的發展,也同樣促進了執行緒的發展。執行緒Thread允許在一個程序中共存多個程式控制執行流程(多個streams)。他們共享程序範圍內的資源,比如說儲存,檔案控制代碼。但是每個執行緒都有自己的程式計數器、棧和本地變數。在多處理器系統中執行緒們也能利用硬體的並行效能力自然地分解開來;在相同程式裡的多個執行緒能夠在多CPU中同步排程執行。

執行緒有時也被稱作輕量級的程序,而且大多數現在作業系統都把執行緒作為排程的基本單位,而不是程序。在沒有明確協調的時候,執行緒同步和非同步的執行都會考慮到對方。從執行緒開始共享他們在所屬程序的儲存地址空間,同一程序的所有的執行緒都能獲得同一變數、從同一堆中分配到物件,這些方式比程序間機制更細粒化的共享了資料。但是如果沒有明確的同步規範來控制協調對共享資料的操作的話,一個執行緒可能會在另一個執行緒使用某個變數的過程中進行修改,對造成不可預料的後果。

1.2從執行緒中受益

如果能夠合理地使用多執行緒,將能夠縮減複雜應用程式的開發和維護成本,並能提供更好的效能。通過將非同步工作流轉換為多個序列化工作流,多執行緒可以更好地對人類的工作和互動方式建模。使用多執行緒,很多複雜的程式碼將變得更加直截了當,因此更容易編寫、閱讀和維護。 在圖形使用者介面程式中使用多執行緒可以提高介面響應速度,在伺服器程式中使用多執行緒可以提高資源利用率和吞吐量。多執行緒還可以簡化 JVM 的設計,垃圾回收器一般在一個專用執行緒中工作。大多數卓越的 Java 應用程式都在某種程度上依賴於多執行緒。

1.2.1利用多處理器的處理能力

多處理器計算機系統曾經非常昂貴和稀有,只用在大型資料中心和科學計算基礎設施中。今天它們更加便宜和豐富,即使是低端伺服器和中檔桌面計算機系統也往往擁有多個處理器。這種趨勢只會增加,因為增加處理器的時鐘頻率(時鐘頻率:指同步電路中時鐘的基礎頻率,是評定CPU的重要指標)越來越困難,處理器製造商將選擇在一個處理器中包含更多的核心。所有的主流晶片製造商都已經開始了這種轉變,並且我們已經目睹了一些擁有很多個處理器的計算機的出現。由於最基本的排程單元是執行緒,只擁有一個執行緒的程式一次最多隻能在一個處理器上執行。在一個擁有兩個處理器的計算機系統中,單執行緒程式放棄了一半的處理器資源。在一個擁有 100 個處理器的計算機系統中,單執行緒程式放棄了99%的處理器資源。另一方面,擁有多個執行緒的程式,同時可以在多個處理器中 執行。如果設計得比較合理,多執行緒程式可以更有效地利用處理器資源,從而增 加程式的吞吐量。 即使在單處理器計算機系統中,使用多執行緒也可以幫助提高吞吐量。如果一個程式是單執行緒的,在等待一個非同步輸入輸出操作完成的時候,處理器處於空閒狀態。如果該程式是多執行緒的,另一個執行緒就可以利用這個時間段來執行(這就類似於一邊讀報紙一邊等待水沸,而不是等水沸了之後再讀報紙)。

1.2.2簡化建模

當你只有一種型別工作要做的時候,你更容易管理時間。如果你只有一種工作要做,你可以從第一件開始逐個完成,直到完成最後一件。你不必耗費精力來確定下一件要做的工作是什麼。另一方面,管理多個不同優先權和截止期限的工作,並在不同型別的工作之間切換,需要一些額外的開銷。對於軟體來說也是如此,相比於同時管理多個不同型別任務的程式,一個管理一種型別任務的程式編寫起來更簡單,更不容易出錯,更容易測試。一個複雜的非同步工作流可以分解成多個簡單的同步工作流,每個工作流在一個單獨的執行緒中執行,只在特定的同步點進行執行緒間通訊。一些框架(例如 Servlet 和 RMI)利用了多執行緒的這種好處。由框架來處理請求管理、執行緒建立、負載均衡等細節問題。Servlet 的編寫者不需要擔心同時 有多少其他請求被處理或者輸入輸出流是否阻塞等問題。當 Servlet 的 Service 方法被呼叫的時候,它可以將對該請求的響應當做一個單執行緒程式。這簡化了 Servlet 元件的開發並削減了該框架的學習難度。

1.2.3簡化非同步事件的處理

一個伺服器應用程式可以從多個遠端客戶端接受 Socket 連線,如果為每個連線都分配一個單獨的執行緒,並使用阻塞式 I/O,這樣的程式更容易開發。

如果一個程式從 Socket 中讀取資料,但是 Socket 中沒有資料,那麼這個 read 方法就會阻塞,直到 Socket 中有資料可用。如果在單執行緒程式中,這不僅意味著相應的請求的處理被拖延,其他請求的處理也會被拖延。為了避免這個問題,單執行緒伺服器程式被迫使用非阻塞式 I/O,相比於阻塞式 I/O 它更復雜也更容易出錯。然而,如果每個請求都有自己的執行緒,那麼一個執行緒的阻塞不會影響到其他請求。 由於歷史原因,作業系統一般只允許一個程序擁有幾百個或者更少的執行緒。作業系統提供了有效的基礎設施(能力)來多路複用 I/O,例如 Unix 系統中的 select 和 poll 系統呼叫方法,Java 類庫中提供了 java.nio 包來呼叫這些提供的能力。然而,作業系統開始逐漸支援更大數量的執行緒,使得為每個客戶端分配一個執行緒的策略變為現實,即使是在擁有大量客戶端的平臺中。

1.2.4.提供給使用者介面更好的響應能力

圖形化使用者介面(GUI)過去是單執行緒的,這意味著你必須經常輪詢整個程式碼,檢視是否有輸入事件觸發,或者間接地通過“主要事件迴圈”執行所有程式。如果主事件迴圈中呼叫程式碼的執行花了太多的時間,那麼在這塊程式碼返回之前,使用者介面會顯示出被“凍結”的狀態。因 為在把執行的控制權返回主事件迴圈之前,無法處理接下來的使用者介面事件。

如今的GUI框架,例如 AWT 和 Swing 工具箱,都使用事件分發執行緒來替換主事件迴圈。當一個使用者介面事件比如一個單擊按鍵事件觸發的時候,在一個單獨的事件執行緒中應用程式定義好的事件處理器會被呼叫。大多數GUI框架都是單執行緒子系統,所以作為父系統的主事件執行緒還在有效的工作,但是事件分發的執行緒卻處於 GUI 工具箱的控制之下,而不是處於應用程式的控制之下。

如果在事件處理器的執行緒中只執行“短命”(原文這裡是short-lived無引號)任務,使用者介面就能合理快速的響應使用者的操作行為。然而,如果在事件處理器的執行緒中執行一個耗時的任務,比如說對大檔案進行拼寫檢查或者從網路上拉取資源,就會損害響應能力。如果使用者在任務執行的過程中又做了個行為操作,在事件處理執行緒能夠執行這個行為或者只是確認它之前會有一個很長的延遲。更糟糕的是,不僅UI介面沒有響應,即使是介面上有取消按鈕,你也無法取消這個正在執行的耗時的任務,因為此時事件分派執行緒正在忙碌,無法響應取消按鈕的單擊事件。但是如果耗時任務如果能分離出來開一個執行緒來執行的話,事件分派執行緒就能保持空閒狀態去執行UI事件,這都保持了UI更好的響應能力。

1.3執行緒的風險

Java 提供的對多執行緒的內建支援是一把雙刃劍。儘管它為多執行緒提供了語言和庫的支援以及一個跨平臺的記憶體模型(正是這個優秀的跨平臺記憶體模型使我們能夠開發一次,得到的java應用各個平臺都能執行),簡化了多執行緒應用程式的開發,但是它也對程式設計者提出了更高的要求,因為越來越多的程式將會使用多執行緒。多執行緒比較深奧,併發也隨之成為了“高階”主題,現在,主流開發者必須清楚認識到執行緒安全的問題。

1.3.1.安全隱患

執行緒安全問題可能變得意想不到地微妙,因為在缺少合理的同步機制的情況下,多執行緒的執行順序是不可預知的,有時甚至是令人驚訝的。下面的程式本來想產生一列無重複的整數值,在單執行緒環境中執行正常,在多執行緒環境中卻執行失敗。這個程式演示了多執行緒交錯執行可能導致不符合我們需要的的結果。

 

上例在多執行緒環境中失敗的原因是,在某些時候,兩個執行緒呼叫 getNext() 方法的時刻非常接近,以至於返回的是同一個數值。value++看似是一個操作,實質上是三個操作:讀取 value 值,value 值加 1,重設 value 值。由於多個執行緒中的操作在執行時可以任意地交錯,可能出現兩個執行緒同時獲得的是相同數值的 value,然 後各自都加 1 的情況。結果就是在不同執行緒中的呼叫返回了相同的結果。

圖1.1中圖片所描述的就是不同執行緒交錯處理。在這些圖表中,時間從左到右依次執行,每一行代表一條不同的執行緒的所有活動,這些交錯的圖片描述出了最糟糕的案例,這個案例展現了在特定順序下發生的錯誤設想結果的危險性。

UnsafeSequence使用了一個不標準的註解:@NotThreadSafe,這個註解是定義好的註解之一,這些註解在整本書中都有應用,用來記錄類或者類成員的併發的屬性。(別的類級別的註解還包括@ThreadSafe和@Immutable,可看備註A檢視細節)。對於多數讀者來說,執行緒安全文件註釋是非常有用的。如果一個類被@ThreadSafe註釋,使用者們可以在多執行緒環境下放心的使用,維護者們也能夠注意到為執行緒安全提供必需的保證,軟體分析工具也能鑑別程式碼裡可能的錯誤。

UnsafeSequence這個類簡單演示了一種常見的併發風險,叫做競爭條件。當被多個執行緒呼叫時,nextValue()方法是否返回一列無重複的整數值取決於多執行緒在執行時的交錯情況,這種不確定性不是我們希望看到的。

由於多執行緒共享同樣的記憶體空間,並且併發執行,它們可以訪問並修改其他執行緒正在使用的變數。這樣極其方便,因為相比於其他執行緒間通訊機制這種方式使變數共享變得更簡單。但共享變數也有極大的風險,資料可能會以不按我們要求進行的方式被修改掉,由於允許執行緒訪問修改相同的變數,把非順序性元素引入到順序化的結構模型中,導致一些很難找出原因的 Bug。為了讓多執行緒程式的行為具有可預測性,對共享變數的訪問必須被合理地協調控制,這樣能保證一個執行緒對該變數的訪問不會干擾到另一個執行緒。幸運的是,Java 提供了同步機制來協調控制對共享變數的訪問。

UnsafeSequence類裡為 getNext()方法加上 synchronized 修飾符,解決不幸的衝突,上述程式碼可以被修復為如下程式碼:

如果沒有synchronized關鍵字(比如將變數快取在暫存器或者處理器本地快取中、讓它不被其他執行緒可見這樣的功能),編譯器、硬體以及執行時將擁有很大的自由來安排程式碼中操作執行的順序和時機。這些優化技巧是為了幫助提高執行速度,但是給開發者增加了負擔,他們必須明確地確認好多執行緒所共享的變數放置在哪裡,這樣才能保證這些優化手段不會破壞安全性。(第16章會給出JVM是如何確保順序以及同步是如何影響的,但是要是你能採用章節2和章節3的規則,你就能安全的避開這些低階細節)

1.3.2.活躍性風險

在開發併發程式碼的時候一定要注意執行緒安全問題,執行緒安全性是不能妥協的。不僅多執行緒程式需要注意安全性,單執行緒程式也需要注意安全性和正確性,當然啦,多執行緒的使用確實引入了額外的安全風險。活躍性故障也會類似地隨著多執行緒的使用產生,這在單執行緒程式中是不存在的。

如果說“安全”意味著“什麼壞事都沒發生”,活躍性關注的就是額外附加的目標--“最終會有一些好的事情發生”。當一個程式行為到達了永遠無法繼續執行前進下去的狀態的時候,就意味著活躍性故障產生了。在單執行緒程式中有一種活躍性故障的形式,是由無限迴圈造成的,導致迴圈之後的程式碼永遠無法被執行。多執行緒的引入也會增加了活躍性故障發生的可能性。例如執行緒A 在等待一個資源,該資源被執行緒 B 排他性地佔有了,並且執行緒B永遠不釋放該資源,那麼執行緒A必須永遠等待下去,這就是一種活躍性故障。本書在第十章將會描述各種形式的活躍性故障,以及如何避免它們,包括死鎖、飢餓、活鎖。就像大多數併發 Bug 一樣,由活躍性故障引起的 Bug 往往難以鎖定,因為它們依賴於不同執行緒中事件發生的相對時機,因此在開發和測試過程中,這種 Bug會產生有時候有問題、有時候沒問題的現象。

1.3.3. 效能風險 

和活躍性相關的就是效能。活躍性意味著一些比較好的事情最終會發生--或者是不夠好的結果最終發生了--不管怎麼樣我們都希望好的結構快點出現。效能問題包含一大堆其他問題,包括服務時間差、響應速度、吞吐量、資源消耗量和可伸縮性。就像安全性和活躍性問題一樣,多執行緒程式不僅要面對單執行緒程式中所有的效能風險,還要面對由多執行緒引入的效能風險。

在設計良好的併發程式中,多執行緒的使用可以提高效能,但是多執行緒會增加執行時開銷。在多執行緒程式中排程器經常需要臨時掛起一個執行緒,執行另一個執行緒,這被稱為上下文切換。上下文切換會造成很大的開銷:儲存和恢復執行上下文、本地損耗、排程執行緒替代執行的執行緒都需要時間。執行緒間的同步機制將會阻礙編譯器對程式碼的優化、阻止記憶體緩衝區的清空和驗證、在共享記憶體的總線上增加了所需要的同步流量,這些因素都會降低多執行緒程式的效能。第十一章將會介紹一些技術來分析並減少這些不利因素。

1.4. 多執行緒無處不在

即使你從沒有顯式地建立一個執行緒,框架也會代表你建立一些執行緒,並且這些執行緒呼叫的程式碼一定要是執行緒安全的。這對開發人員造成了很大的設計和實現負擔。因為開發執行緒安全類相比於非執行緒安全類更困難,需要付出更多的精力。

每一個 Java 程式都是多執行緒的,因為當 JVM 啟動的時候它建立了一些執行緒用來負責一些內部的工作(例如垃圾回收執行緒、釋放資源)和 一個Main 執行緒。Main 執行緒用來執行 main 函式中的程式碼。AWT、Swing 等使用者介面框架會建立一個執行緒用來管理使用者介面事件。Timer 類會建立一個執行緒用來執行被延遲的任務。像Servlet或者 RMI框架會建立執行緒池來執行框架元件中的方法。

如果你像很多其他開發者那樣使用這些框架的話,你必須對併發和執行緒安全比較熟悉,因為這些框架建立了多執行緒,並在這些執行緒中呼叫你開發的元件。理想情況是將多執行緒看做是 Java 的高階或者可選的特性,並不是必須掌握的,但是現實情況是,所有的 Java 程式都是多執行緒的,並且這些框架的使用並不能使你完全不用考慮多執行緒問題。

當你使用了一個帶併發特性的框架(比如 Servlet)的時候,往往很難將併發限制於框架程式碼中,因為框架總是要使用回撥來呼叫你編寫的元件,從而來改變元件的內部狀態。類似地,對執行緒安全性考慮不僅僅對是在框架呼叫元件後結束,在元件修改程式狀態的過程中但凡涉及到的程式碼執行路徑上的類都要考慮執行緒安全性。因此,執行緒安全性需求是有傳播性質的。

框架的執行緒呼叫應用程式中的各個組成部分會把併發引入到整個應用中。元件總是訪問應用程式的狀態,因此需要所有程式碼能夠保證狀態這個引數一定是執行緒安全的。

下面介紹的所有功能都會導致你編寫的程式中的一些程式碼在其他的執行緒中被呼叫,這些執行緒並不是由應用程式管理的。儘管執行緒安全性需求起源於這些功能,但卻不會因為功能停止而終止需求,這些需求將會像水面漣漪一般擴散至整個應用中。

Timer 類

Timer 類是一個方便的機制,用來一次性或週期性呼叫定時任務。Timer 類的引入會使得原本序列化的程式變得複雜,因為TimerTask 是在 Timer 管理的某個執行緒中執行的,而不是在應用程式所管理的。如果某個TimerTask訪問了一個被其他執行緒訪問的資料,兩者都必須以執行緒安全的形式進行訪問。通常來說最簡單的辦法就是讓被 TimerTask 訪問的物件本身就是執行緒安全的,也就是說將執行緒安全性封裝在共享物件中。l

Servlet 和 JSP

Servlet 框架用來部署 Web 應用程式並將遠端 HTTP 請求分發到不同的執行緒中執行。一個請求在到達伺服器後將會被分發,然後有可能會通過一組過濾器,最終到達合適的Servlet或者JSP。每個Servlet就是一個應用邏輯元件,在高訪問量的伺服器中很有可能出現多個客戶端同時訪問同一個Servlet的情況。Servlet規格要求說明中要求Servlet能夠同時被多執行緒呼叫,換句話說,必須是執行緒安全的。

即使在一個Web應用程式中,你可以確定某個時刻Servlet同時只會在一個執行緒中執行,你還是要注意執行緒安全問題。Servlet總是允許和其他Servlet共享狀態資訊,例如儲存在 ServletContext 中的應用程式域物件或者儲存在HttpSession中的session域物件。如果說一個servlet允許和其他servlet或者請求共享物件,那他就需要確保當不同的執行緒同時訪問這些物件的時候,能夠恰當的協調好對這些物件的訪問。這些共享物件(Servlets、JSPs、servlet過濾器、物件等)也需要儲存在能夠確保執行緒安全的諸如ServletContext、Httpsession的域容器中。 l

RMI

RMI允許你呼叫另一個 JVM 中物件的方法,當你使用 RMI 呼叫遠端方法的時候,方法引數會被打包成位元組流,通過網路傳送到遠端 JVM 中,然後被還原為物件或原始資料型別,傳送給遠端方法。

當遠端物件的方法被呼叫的時候,是在哪個執行緒中呼叫的?你可能並不清楚,但他一定不是你建立的執行緒--而是在一個由RMI管理的執行緒被呼叫。同一個遠端物件的同一個遠端方法會被多個RMI執行緒同時呼叫嗎?

遠端物件必須防範兩個執行緒安全問題:被多個遠端物件共享的物件應該是執行緒安全的,遠端物件本身應該是執行緒安全的。像servlets、RMI物件都要能保證自己在被多個執行緒呼叫時是執行緒安全的。 l

Swing 和 AWT

GUI 應用程式與生俱來就是非同步的。使用者可能在任何時候選擇一個選單項或者按下一個按鈕,並且使用者希望應用程式即便是在執行任何任務的過程中都能夠立即響應使用者介面操作。Swing 和 AWT 通過建立一個獨立的用於處理使用者介面事件和更新圖形介面的執行緒來解決這個問題。

Swing 元件,例如 JTable 不是執行緒安全的。替代的手段是,Swing 程式通過將所有對 GUI 的訪問限制在事件響應執行緒中來達到執行緒安全的目的。如果一個程式想要在事件響應執行緒之外操作 GUI 的話,必須讓操作 GUI 的程式碼在事件響應執行緒中執行。

當用戶在 GUI 上進行了某個操作,事件響應執行緒中某個事件處理函式被呼叫來執行使用者的需求。如果這個事件處理函式需要訪問被其他執行緒共享的物件,那麼事件處理函式和其他一起共用的物件那些執行緒都必須考慮執行緒安全問題。

如有轉載或引用請註明出處!!!!!如果做商業用途必追究責任!!!!

相關推薦

JAVA-CONCURRENCY IN PRACTICE章節翻譯

參考了很多童老師團隊的翻譯,自己也看英文對照,有修改 章節一: 寫一個正確的程式,難,寫一個正確的併發程式,難上加難。相比於非併發程式(個人理解是單執行緒那種的),併發程式裡有更多容易產生錯誤的地方。那麼為啥我們還要這麼費勁研究併發呢?因為執行緒Thread是java

Is "Java Concurrency in Practice" still valid in the era of Java 8 and 11?

One of my reader Shobhit asked this question on my blog post about 12 must-reads advanced Java books for intermediate programmers - part1. I really like t

Java Concurrency in Practice中物件鎖重入問題的理解

原因:Java Concurrency in Practice 中文版21頁講解了關於物件鎖的重入的問題,一直沒有讀懂作者給的例子,今天琢磨了好久,找到了一個可以說服自己的理由…… 1 原書內容如下: 當某個執行緒請求一個由其他執行緒持有的鎖時,發出

深入瞭解Java併發——《Java Concurrency in Practice》14.構建自定義的同步工具

雖然章節的目的是介紹如何基於AQS等基類來構建自定義的同步工具,但詳細的介紹了AQS的原理,並且詳細的講解了java.util.concurrent類庫中許多基於AQS的常用同步工具對AQS的實現及原理。瞭解AQS之後對ReentrantLock、Sema

thinking in java (六) ----- 內部類(,Inner classes)

將某個class定義置於另一個class定義之中是可行的,這就是內部類。 內部類基礎 內部類一般來說包括以下幾種:成員內部類,區域性內部類,匿名內部類,靜態內部類。 成員內部類 成員內部類是最普通的內部類,定義在一個外部類的內部,如下: class Cir

final關鍵字 ——Thinking in Java學習筆記(十

final的使用情況一般分為三種:資料、方法、類 final資料 final修飾的資料表示值不可變,引用不能改變。其中,對資料的修飾又分為: 1、final成員變數:由final修飾的類成員變數,如果是基礎資料型別就表示不能改變它的值,但如果是已經初始化了的引用

章節 Java開發準備

課時一:發展歷史 1、具體內容         Java是一門程式語言,Java已經成為了事實意義上的程式的開發標準結構。         2003年的時候出了一件很有意義的事情,據說有一個美國的衛星專案上使

java高級工程師(

jsb http協議 html tel url 實現負載均衡 為什麽 行為 get 一、無筆試題 不知道是不是職位原因還是沒遇到,面試時,都不需要做筆試題,而是填張個人信息表格,或者直接面試 二、三大框架方面問題 1、Spring 事務的隔離性,並說說每個

JAVA基礎實例(

actor oid 其它 返回 prime i++ con bsp factorial 1寫一個方法,用一個for循環打印九九乘法表 /** *一個for循環打印九九乘法表 */ public void nineNineMultiTable() { for

Java基礎知識整理(

顯式 sys 轉換 強制 print pri 字符 parse ger Java開發環境JDK(Java編輯器、Java運行工具(JRE作用)、Java文檔生成工具、Java打包工具) 1.Java是嚴格區分大小寫的。2.Java程序中一句連續的字符串不能分開在兩行書寫,

Java線程詳解()

線程 thread runnable 程序、進程、線程的概念 程序(program):是為完成特定任務、用某種語言編寫的一組指令的集合。即指一段靜態的代碼,靜態對象。 進程(process):是程序的一次執行過程,或是正在運行的一個程序。動態過程:有它自身的產生、存在和消亡的過程。 如

java 基本程序設計結構

border amp 範圍 order 變量名 15位 錯誤 lca 標準   首先Java區分大小寫。如果出現了大小寫拼寫錯誤,程序無法運行。   java 變量名字必須以字母開頭,後面可以跟字母數字的任意組合。長度基本上沒有限制。但是不能使用java保留字。   標準的

Java多線程系列——Java實現線程方法

多個 true dex extends nds one ash .get for Java實現線程的兩種方法 繼承Thread類 實現Runnable接口 它們之間的區別如下: 1)Java的類為單繼承,但可以實現多個接口,因此Runnable可能在某些場景比Threa

Java反射機制詳解

java 反射 反射機制 工廠模式 1反射機制是什麽反射機制是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱為java語言的反射機制。在面向對象的世界裏,萬事萬物皆對象.在ja

Java多線程(

方法 trace 線程調度 lba 準備 sta pos per 退出 多線程作為Java中很重要的一個知識點,在此還是有必要總結一下的。 一.線程的生命周期及五種基本狀態 關於Java中線程的生命周期,首先看一下下面這張較為經典的圖: 上圖中基本上囊括了Jav

Java之集合初探(

lin 數據改變 排序。 方法 規則 找不到 集合 回收 for循環 一、集合概述、區別 集合是一種容器,數組也是一種容器 在Java編程中,裝各種各樣的對象(引用類型)的叫做容器。 為什麽出現集合類? 面向對象語言對事物的體現都是以對象的形式,所以為了方便對多個對象的操作

Java IO學習總結(

file flush writer directory 創建 str java 資源 tab 一、File 類 Java中不管文件還是目錄都可以使用File類操作,File能新建、刪除、重命名文件和目錄,但是不能訪問文件內容本身,訪問文件內容需要使用輸入輸出流。 Fi

Java總結篇系列:Java多線程(

常見 而是 同時 private 狀態 過程 運行時 不同的 bstr Java總結篇系列:Java多線程(一) 多線程作為Java中很重要的一個知識點,在此還是有必要總結一下的。 一.線程的生命周期及五種基本狀態 關於Java中線程的生命周期,首先看一下下面這張較

java多線程系列()

常用 肩膀 true 人的 設置線程優先級 ++ 好好學習 .get 遠的 java多線程技能 前言:本系列將從零開始講解java多線程相關的技術,內容參考於《java多線程核心技術》與《java並發編程實戰》等相關資料,希望站在巨人的肩膀上,再通過我的理解能讓知識更加簡

java獲取上周任意天的日期

日期 mon || code 第一天 pre 周幾 locale log public static Date getDayOfWeek(int dayOfWeek,int weekOffset){ if(dayOfWeek>Calendar.S