原創|行業資訊|編輯:龔雪|2014-05-22 09:40:35.000|閱讀 391 次
概述:介紹了解ava并發編程原理,工作狀態,模塊模式等,從而快速掌握Java并發編程,并附上各種資源工具。
# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
Java作為最流行的編程語言之一,隨著 Java 8的到來,越來越多的人開始學習,并深入研究!下面將介紹 Java并發編程,讓開發者在最短的時間里掌握并發編程。
1.1. 什么是并發?
并 發是一種能并行運行多個程序或并行運行一個程序中多個部分的能力。如果程序中一個耗時的任務能以異步或并行的方式運行,那么整個程序的吞吐量和可 交互性將大大改善。現代的PC都有多個CPU或一個CPU中有多個核。是否能合理運用多核的能力將成為一個大規模應用程序的關鍵。
1.2. 進程 vs 線程
進程是以獨立于其他進程的方式運行的,進程間是互相隔離的。一個進程無法直接訪問另一個進程的數據。進程的資源諸如內存和CPU時間片都是由操作系統來分配。
線程又被稱為輕量級進程。每個線程有它獨自的調用棧, 但是在同一進程下的線程又能互相訪問它們間的共享數據。每個線程都有它獨自的緩存。如果一個線程讀取了某些共享數據,那么它將這些數據存放在自己的緩存中以供將來再次讀取。
一個 Java應用程序默認以一個進程的形式運行著。在一個 Java程序中,你將協同多個不同的線程一起完成并行運算或實現異步行為。
2.1. 并發性能的上限
之所以并發號稱能較快的完成某些任務是因為這些任務能被分組成多個子任務,并且這些子任務能被并行的執行。所以一個任務的實際運行效率將受限于該任務中能并行執行的部分。
一個程序理論上可達到的最高并發性能可通過以下一個被稱為Amdahl 定律來計算出:
設F為一個程序中不能被并行執行的百分比,N是處理器的數量,那么理論上該程序能獲得的最高并發性能將可能是1/ (F+ ((1-F)/n)).
2.2. 并發問題
線程有獨自的調用棧,但是又能互相訪問共享的數據。所以這里你會遇到兩個問題,可見性和訪問。
可見性問題發生于如果線程A先讀取了某些共享數據,之后線程B對這些數據進行了修改,那么線程A可能看不到線程B對這數據的改動。
訪問問題發生于于多個線程同時訪問修改同一個共享數據。可見性及訪問問題將導致:
活躍性失敗——由于并發訪問數據導致程序無任何反應。 譬如,死鎖。
安全性失敗——程序創建了錯誤的數據。
3.1. 進程與線程
一個 Java程序默認以一個線程運行在自己的進程中。 Java語言通過Thread相關代碼來支持線程。 Java程序可通過Thread這個類來創建線程。從 Java1.5起,在 Java.util.concurrent中提供了改進的并發庫。
3.2. 鎖和線程同步
Java提供了“鎖” 機制來保護代碼片段免于被多個線程在同一時刻運行。最簡單的鎖住一個方法或一個類就是在該方法或類前添加synchronized關鍵字
保證了在Java中synchronized關鍵字保證了在同一時刻,只有單個線程能訪問這塊代碼,每個進入這同步代碼塊的線程都將能看到之前持有相同鎖進入的線程的所做的改動.對于線程間的可靠通訊及互斥訪問 來說,同步是非常必要的
你可以在定義方法時使用synchronized關鍵字。這個關鍵字保證了同一時刻只有一個線程能運行這個方法。其他同樣調用了這個方法的線程將被阻塞直到第一個線程離開這個方法。
1 public synchronized void critial() { 2 // some thread critical stuff 3 // here 4 }
你同樣也能用synchronized關鍵字來保護方法中的代碼塊。這塊代碼將由一個關鍵對象來保護,該關鍵對象可以是個string或其他object。這個關鍵對象就被稱為 lock。所有被相同lock保護的代碼在同一時刻只能被單個線程執行。
舉例來說,以下的數據結構將保證同時只有單個線程可以訪問add和next方法:
01 package de.vogella.pagerank.crawler; 02 03 import Java.util.ArrayList; 04 import Java.util.List; 05 /*** Data structure for a web crawler. Keeps track of the visited sites and keeps 06 * a list of sites which needs still to be crawled. 07 * @author Lars Vogel 08 */ 09 public class CrawledSites { 10 private List<String> crawledSites = new ArrayList<String>(); 11 private List<String> linkedSites = new ArrayList<String>(); 12 13 public void add(String site) { 14 synchronized (this) { 15 if (!crawledSites.contains(site)) { 16 linkedSites.add(site); 17 } 18 } 19 } 20 /** * Get next site to crawl. Can return null (if nothing to crawl) */ 21 public String next() { 22 if (linkedSites.size() == 0) { 23 return null; 24 } 25 synchronized (this) { 26 <em>// Need to check again if size has changed</em> 27 if (linkedSites.size() > 0) { 28 String s = linkedSites.get(0); 29 linkedSites.remove(0); 30 crawledSites.add(s); 31 return s; 32 } 33 return null; 34 } 35 } 36 37 }
3.3. Volatile
如果一個變量聲明時使用了volatile 關鍵字,那么該關鍵字保證了,任何讀取該變量的線程都將讀到最新寫進該變量的值。但volatile 關鍵字不會保證變量上的任何互斥訪問。
因為在 Java 5中,對一個聲明了volatile 的變量進行寫操作會導致該寫操作所在該線程之前所有的對非volatile 變量的修改進行同步更新。這也可用來更新引用類型變量。例如,有個volatile 類型的變量person。你必須創建一個臨時變量person,然后調用SETTER方法來初始化這變量然后將臨時變量賦值給final變量。 這會使這個變量的地址發生改變并且此變量的值對于其他線程變為可見。
4.1. 概覽
Java內存模型描述了線程內存與主存間的通訊關系。
Java內存模型定義了線程內的內存改變將怎樣傳遞到其他線程的規則,同樣也定義了線程內存與主存進行同步的場景,也描述了哪些操作屬于原子操作及操作間的順序。
4.2. 原子操作
一個原子操作是指一個執行時不會被其他操作影響到的最小單位的操作。
Java語言規范保證了對一個變量的讀和寫操作都是原子的(除了LONG和DOUBLE類型的變量)。對于LONG或DOUBLE類型的變量,只有當這些變量聲明時使用了volatile關鍵字才是原子的
假設定義了一個INT變量I,那么在 Java中,I++操作不是一個原子操作。同樣,這對于其他數字類型的變量也都不是一個原子操作。
I++操作先從I中讀取了當前值(這是個原子操作)然后再讓它加上1寫回(原子操作)。但是在讀和寫這兩個操作間,I的值有可能被改變。
從 Java1.5起, Java提供了原子變量,例如AtomicInteger 或 AtomicLong 都提供了類似 getAndDecrement(), getAndIncrement() 及 getAndSet()等原子方法。
4.3.同步代碼塊的內存更新
Java內存模型保證了每個進入相同鎖同步塊的線程都能看到之前進入的其他所有線程修改的結果。
溫馨小提示:好的資源,在 Java開發中能事半功倍!
Java并發編程基礎://ifeve.com/java-concurrency-cookbook/
業界被公認為最好的Java開發平臺:IntelliJ IDEA
最實惠、綜合全面的J2EE IDE與Web開發工具套件:MyEclipse
多平臺Java安裝文件生成工具:install4j
全面測試Java程序的工具:Parasoft Jtest
本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn