當前位置:首頁 » 編程軟體 » c並發編程經典實例pdf

c並發編程經典實例pdf

發布時間: 2024-07-08 01:58:07

1. 為什麼需要使用並發編程什麼時候適合使用並發編程技術

  • 提高計算效率,充分利用計算機性能。

  • 為大數據處理做好准備。

2. 鍗佷釜緇忓吀鐨凜寮婧愰」鐩浠g爜

鎺㈢儲C璇璦鐨勭紪紼嬪疂搴擄細鍗佸ぇ緇忓吀寮婧愰」鐩浠g爜鎺ㄨ崘


鍦ㄥ紑婧愮殑涓栫晫閲岋紝C璇璦鐨勯瓍鍔涗笉璦鑰屽柣銆備綔涓哄簳灞傜紪紼嬭璦錛孋鐨勭伒媧繪у拰鏁堢巼涓哄紑鍙戣呬滑鎻愪緵浜嗘棤絀風殑鍙鑳姐備互涓嬫槸鍗佷釜綺懼績鎸戦夌殑錛屾棦杞婚噺綰у張緇忓吀鐨凜寮婧愰」鐩錛屽畠浠涓嶄粎鏄鎶鏈瀛︿範鐨勭懓瀹濓紝鏇存槸紼嬪簭鍛樻垚闀跨殑鍨鑴氱煶銆



  1. Webbench - 綆鍗曢珮鏁堢殑緗戠珯鍘嬪姏嫻嬭瘯宸ュ叿

    Webbench鏄涓嬈劇敤C璇璦緙栧啓鐨凩inux涓嬭交閲忕駭宸ュ叿錛屽畠浠ヤ笉鍒600琛岀殑浠g爜妯℃嫙澶ч噺騫跺彂榪炴帴錛屽府鍔╀綘嫻嬭瘯緗戠珯鐨勮礋杞借兘鍔涖傚叾婧愮爜綆媧佹槑浜嗭紝鏄鐞嗚В緗戠粶鍘嬪姏嫻嬭瘯鍩虹鐨勫ソ渚嬪瓙銆傛兂娣卞叆浜嗚В錛熻塊棶錛http://home.tiscali.cz/~cz210552/webbench.html



  2. Tinyhttpd - 鏋佺畝HTTP鏈嶅姟鍣

    浠502琛屼唬鐮侊紙鍚娉ㄩ噴錛夌殑Tinyhttpd錛屾槸鍏ラ棬HTTP鏈嶅姟鍣ㄧ紪紼嬬殑緇濅匠鏁欐潗銆傚畠璁╀綘涓紿ユ湇鍔″櫒鏍稿績錛屼唬鐮侀噺鉶藉皯錛屼絾鍔熻兘瀹炵敤銆備笅杞藉湴鍧錛http://sourceforge.net/projects/tinyhttpd/



  3. cJSON - JSON緙栬В鐮佸櫒鐨勮交閲忕駭閫夋嫨
    cJSON鏄疌璇璦涓鐨勮交閲忕駭JSON搴擄紝500澶氳屼唬鐮佹棦楂樻晥鍙堟槗鎳傘傝櫧鐒跺姛鑳芥湁闄愶紝浣嗗叾灝忓閥鍜岄熷害浣垮叾鎴愪負瀛︿範C欏圭洰鐨勭悊鎯寵寖渚嬨傞」鐩涓婚〉錛http://sourceforge.net/projects/cjson/

  4. CMockery - 鍗曞厓嫻嬭瘯杞婚獞鍏
    Google鍑哄搧鐨凜Mockery錛屼竴涓杞婚噺綰х殑C鍗曞厓嫻嬭瘯妗嗘灦錛3K琛屼唬鐮佸唴錛屼綘灝嗛嗕細鍒版祴璇曢┍鍔ㄥ紑鍙戠殑欖呭姏銆傚畠鐨勬槗鐢ㄦу拰鍏煎規т嬌鍏舵垚涓哄祵鍏ュ紡寮鍙戣呯殑鐞嗘兂閫夋嫨銆傛洿澶氳︽儏錛http://code.google.com/p/cmockery/downloads/list


緇х畫娣卞叆錛屼綘灝嗗彂鐜幫細



  1. Libev - 浜嬩歡椹卞姩緙栫▼鐨勯珮鏁堜箣閫
    Libev鏄涓涓鍩轟簬epoll鍜宬queue鐨勯珮鏁堜簨浠跺簱錛4.15鐗堟湰鍙鏈8000澶氳屼唬鐮侊紝鏄瀛︿範浜嬩歡椹卞姩緙栫▼鐨勭粷浣寵祫婧愩備簡瑙f洿澶氾細http://software.schmorp.de/pkg/libev.html

  2. Memcached - 緙撳瓨緋葷粺涓鐨勬ц兘鏄庢槦
    Memcached鏄涓涓鍒嗗竷寮忓唴瀛樼紦瀛樼郴緇燂紝鐢ㄤ簬鍑忚交鏁版嵁搴撳帇鍔涖1.4.7鐗堟湰浠g爜閲忛備腑錛屽ぇ綰10K琛岋紝蹇閫熸彁鍗囦綘鐨勬暟鎹搴撴ц兘鐞嗚В銆備笅杞藉湴鍧錛http://memcached.org/

  3. Lua - 璇璦綺劇畝鐨勭紪紼嬪吀鑼
    Lua浠g爜杞婚噺鍒頒護浜烘儕鍙癸紝1.5W琛岋紙鍘婚櫎絀虹櫧鍜屾敞閲婏級鐨100% ANSI C浠g爜錛岃╀綘棰嗙暐鏋佺畝璁捐$殑欖呭姏銆備簡瑙f洿澶氾細http://www.lua.org/


鏈鍚庯紝鎴戜滑鏈夛細



  1. sqlite - 綆鍗曢珮鏁堢殑宓屽叆寮忔暟鎹搴
    SQLite錛屼竴涓灝忓瀷鐨勩佽嚜鍖呭惈鐨勩侀浂閰嶇疆鐨凷QL鏁版嵁搴擄紝3涓囪孋浠g爜瀹炵幇寮哄ぇ鍔熻兘銆傚傛灉浣犺拷奼傝交閲忎笌楂樻晥錛屽畠涓嶅歸敊榪囥備笅杞藉湴鍧錛http://www.sqlite.org/

  2. UNIX V6 - 綆鍗曡屽己澶х殑鎿嶄綔緋葷粺鍐呮牳
    UNIX V6鍐呮牳婧愪唬鐮侊紝綰1涓囪屼唬鐮侊紝閫傚悎鍒濆﹁呯悊瑙e拰瀛︿範銆傚畠鉶界畝媧侊紝鍗磋兘璁╀綘浣撻獙鍒版搷浣滅郴緇熷紑鍙戠殑綺鵑珦銆備簡瑙f洿澶氾細http://minnie.tuhs.org/cgi-bin/utree.pl?file=V6

  3. NetBSD - 寮哄ぇ涓旂Щ妞嶇殑UNIX-like緋葷粺
    NetBSD浠ョ畝媧佸拰鍏堣繘鐗規ц岄椈鍚嶏紝瀹冨湪浼楀氬鉤鍙頒笂琛ㄧ幇鍑鴻壊錛屾簮浠g爜瀹屾暣涓旀槗浜庤幏鍙栥傚逛簬鎿嶄綔緋葷粺鐮旂┒鍜屽疄璺碉紝瀹冩槸涓涓鐞嗘兂鐨勯夋嫨銆傝塊棶錛http://www.netbsd.org/


榪欏嶮涓欏圭洰錛屾棤璁轟綘鏄疌璇璦鐨勬柊鎵嬭繕鏄璧勬繁寮鍙戣咃紝閮借兘浠庝腑鑾風泭鍖嫻咃紝璁〤璇璦鐨勭紪紼嬩箣鏃呮洿鍔犱赴瀵屾湁瓚c

3. c璇璦奼傚鉤鍧囧

c璇璦奼傚鉤鍧囧兼ラゅ備笅錛

1銆佹墦寮Excel紼嬪簭錛屽壋寤轟竴涓鏂扮殑宸ヤ綔綈挎垨鎵撳紑涓涓宸叉湁鐨勫伐浣滅翱銆

2銆佸湪宸ヤ綔綈誇腑鎵撳紑浣犺佹搷浣滅殑宸ヤ綔琛ㄣ備綘鍙浠ラ氳繃鍦ㄥ伐浣滅翱紿楀彛涓鐐瑰嚮宸ヤ綔琛ㄥ悕縐版潵鍒囨崲宸ヤ綔琛ㄣ

3銆佺『璁や綘鐨勬暟鎹宸茬粡杈撳叆鍒拌〃鏍間腑銆傚傛灉浣犺繕娌℃湁杈撳叆鏁版嵁錛岃峰厛杈撳叆浣犵殑鏁版嵁銆

4銆侀夋嫨浣犺佹坊鍔犲鉤鍧囧垎鍒楃殑琛屻備綘鍙浠ラ氳繃鐐瑰嚮琛屽彿鏉ラ夋嫨鏁磋岋紝鎴栬呮寜浣廠hift閿鍚屾椂鐐瑰嚮琛屽彿鏉ラ夋嫨澶氳屻

3銆佹硾鍨嬬紪紼嬶細娉涘瀷緙栫▼鏄涓縐嶇紪紼嬭寖寮忥紝瀹冨己璋冪畻娉曞拰鏁版嵁緇撴瀯鐨勯氱敤鎬у拰鐏墊椿鎬с侰璇璦涓鐨勬硾鍨嬬紪紼嬫秹鍙婂埌浣跨敤瀹忓拰鍑芥暟鎸囬拡絳夋妧鏈銆傞氳繃浣跨敤瀹忥紝鍙浠ュ畾涔夊彲閫傜敤浜庡氱嶆暟鎹綾誨瀷鐨勫嚱鏁幫紱閫氳繃浣跨敤鍑芥暟鎸囬拡錛屽彲浠ョ紪鍐欏嚭鍙閫傜敤浜庡氱嶆暟鎹綾誨瀷鐨勫嚱鏁般

4銆佸苟鍙戠紪紼嬶細騫跺彂緙栫▼鏄涓縐嶇紪紼嬭寖寮忥紝瀹冨厑璁稿氫釜浠誨姟鍚屾椂鎵ц屻侰璇璦涓鐨勫苟鍙戠紪紼嬫秹鍙婂埌浣跨敤澶氱嚎紼嬫垨澶氳繘紼嬫妧鏈銆傚彲浠ヤ嬌鐢ㄥ氱嚎紼嬫潵瀹炵幇騫跺彂鎵ц岀殑浠誨姟錛涗篃鍙浠ヤ嬌鐢ㄨ繘紼嬫帶鍒禔PI鏉ュ壋寤哄拰綆$悊瀛愯繘紼嬨

4. java並發常識

1.java並發編程是什麼
1, 保證線程安全的三種方法: a, 不要跨線程訪問共享變數b, 使共享變數是final類型的c, 將共享變數的操作加上同步 2, 一開始就將類設廳搏計成線程安全的, 比在後期重新修復它,更容易。

3, 編寫多線程程序, 首先保證它是正確的, 其次再考慮性能。 4, 無狀態或只讀對象永遠是線程安全的。

5, 不要將一個共享變數 *** 在多線程環境下(無同步高伏羨或不可變性保護) 6, 多線程環境下的延遲載入需要同步的保護, 因為延遲載入會造成對象重復實例化 7, 對於volatile聲明的數值類型變數進行運算, 往往是不安全的(volatile只能保證可見性,不能保證原子性)。 詳見volatile原理與技巧中, 臟數據問題討論。

8, 當一個線程請求獲得它自己佔有的鎖時(同一把鎖的嵌套使用), 我們稱該鎖為可重入鎖。在jdk1。

5並發包中, 提供了可重入鎖的java實現-ReentrantLock。 9, 每個共享變數,都應該由一個唯一確定的鎖保護。

創建與變數相同數目的ReentrantLock, 使他們負責每個變數的線程安全。 10,雖然縮小同步塊的范圍, 可以提升系統性能。

但在保證原子性的情況下, 不可將原子操作分解成多個synchronized塊。 11, 在沒有同步的情況下, 編譯器與處理器運行時的指令執行順序可能完全出乎意料。

原因是, 編譯器或處理器為了優化自身執行效率, 而對指令進行了的重排序(reordering)。 12, 當一個線程在沒有同步的情況下讀取變數, 它可能會得到一個過期值, 但是至少它可以看到那個線程在當時設定的一個真實數值。

而不是憑空而來的值。 這種安全保證, 稱之為最低限的安全性(out-of-thin-air safety) 在開發並發應用程序時, 有時為了大幅度提高系統的吞吐量與性能, 會採用這種無保障的做法。

但是針對, 數值的運算, 仍舊是被否決的。 13, volatile變數,只能保證可見性, 無法保證原子性。

14, 某些耗時較長的網路操作或IO, 確保執行時, 不要佔有鎖。 15, 發布(publish)對象, 指的是使它能夠被當前范圍之外的代碼所使用。

(引用傳遞)對象逸出(escape), 指的是一個對象在尚未准備好時將它發布。 原則: 為防止逸出, 對象必須要被完全構造完後, 才可以被發布(最好的解決方式是採用同步) this關鍵字引用對象逸出 例子: 在構造函數中, 開啟線程, 並將自身對象this傳入線程, 造成引用傳遞。

而此時, 構造函數尚未執行完, 就會發生對象逸出了。 16, 必要時, 使用ThreadLocal變戚拍量確保線程封閉性(封閉線程往往是比較安全的, 但一定程度上會造成性能損耗)封閉對象的例子在實際使用過程中, 比較常見, 例如 hibernate openSessionInView機制, jdbc的connection機制。

17, 單一不可變對象往往是線程安全的(復雜不可變對象需要保證其內部成員變數也是不可變的)良好的多線程編程習慣是: 將所有的域都聲明為final, 除非它們是可變的。
2.Java線程並發協作是什麼
線程發生死鎖可能性很小,即使看似可能發生死鎖的代碼,在運行時發生死鎖的可能性也是小之又小。

發生死鎖的原因一般是兩個對象的鎖相互等待造成的。 在《Java線程:線程的同步與鎖》一文中,簡述死鎖的概念與簡單例子,但是所給的例子是不完整的,這里給出一個完整的例子。

/** * Java線程:並發協作-死鎖 * * @author Administrator 2009-11-4 22:06:13 */ public class Test { public static void main(String[] args) { DeadlockRisk dead = new DeadlockRisk(); MyThread t1 = new MyThread(dead, 1, 2); MyThread t2 = new MyThread(dead, 3, 4); MyThread t3 = new MyThread(dead, 5, 6); MyThread t4 = new MyThread(dead, 7, 8); t1。 start(); t2。

start(); t3。start(); t4。

start(); } } class MyThread extends Thread { private DeadlockRisk dead; private int a, b; MyThread(DeadlockRisk dead, int a, int b) { this。 dead = dead; this。

a = a; this。b = b; } @Override public void run() { dead。

read(); dead。write(a, b); } } class DeadlockRisk { private static class Resource { public int value; }。
3.如何學習Java高並發
1.學習 *** 並發框架的使用,如ConcurrentHashMAP,CopyOnWriteArrayList/Set等2.幾種並發鎖的使用以及線程同步與互斥,如ReentainLock,synchronized,Lock,CountDownLatch,Semaphore等3.線程池如Executors,ThreadPoolExecutor等4.Runable,Callable,RescureTask,Future,FutureTask等5.Fork-Join框架以上基本包含完了,如有缺漏請原諒。
4.並發編程的Java抽象有哪些呢
一、機器和OS級別抽象 (1)馮諾伊曼模型 經典的順序化計算模型,貌似可以保證順序化一致性,但是沒有哪個現代的多處理架構會提供順序一致性,馮氏模型只是現代多處理器行為的模糊近似。

這個計算模型,指令或者命令列表改變內存變數直接契合命令編程泛型,它以顯式的演算法為中心,這和聲明式編程泛型有區別。 就並發編程來說,會顯著的引入時間概念和狀態依賴 所以所謂的函數式編程可以解決其中的部分問題。

(2)進程和線程 進程抽象運行的程序,是操作系統資源分配的基本單位,是資源cpu,內存,IO的綜合抽象。 線程是進程式控制制流的多重分支,它存在於進程里,是操作系統調度的基本單位,線程之間同步或者非同步執行,共享進程的內存地址空間。

(3)並發與並行 並發,英文單詞是concurrent,是指邏輯上同時發生,有人做過比喻,要完成吃完三個饅頭的任務,一個人可以這個饅頭咬一口,那個饅頭咬一口,這樣交替進行,最後吃完三個饅頭,這就是並發,因為在三個饅頭上同時發生了吃的行為,如果只是吃完一個接著吃另一個,這就不是並發了,是排隊,三個饅頭如果分給三個人吃,這樣的任務完成形式叫並行,英文單詞是parallel。 回到計算機概念,並發應該是單CPU時代或者單核時代的說法,這個時候CPU要同時完成多任務,只能用時間片輪轉,在邏輯上同時發生,但在物理上是串列的。

現在大多數計算機都是多核或者多CPU,那麼現在的多任務執行方式就是物理上並行的。 為了從物理上支持並發編程,CPU提供了相應的特殊指令,比如原子化的讀改寫,比較並交換。

(4)平台內存模型 在可共享內存的多處理器體系結構中,每個處理器都有它自己的緩存,並且周期性的與主存同步,為什麼呢?因為處理器通過降低一致性來換取性能,這和CAP原理通過降低一致性來獲取伸縮性有點類似,所以大量的數據在CPU的寄存器中被計算,另外CPU和編譯器為了性能還會亂序執行,但是CPU會提供存儲關卡指令來保證存儲的同步,各種平台的內存模型或者同步指令可能不同,所以這里必須介入對內存模型的抽象,JMM就是其中之一。 二、編程模型抽象 (1)基於線程模型 (2)基於Actor模型 (3)基於STM軟體事務內存 …… Java體系是一個基於線程模型的本質編程平台,所以我們主要討論線程模型。

三、並發單元抽象 大多數並發應用程序都是圍繞執行任務進行管理的,任務是抽象,離散的工作單元,所以編寫並發程序,首要工作就是提取和分解並行任務。 一旦任務被抽象出來,他們就可以交給並發編程平台去執行,同時在任務抽象還有另一個重要抽象,那就是生命周期,一個任務的開始,結束,返回結果,都是生命周期中重要的階段。

那麼編程平台必須提供有效安全的管理任務生命周期的API。 四、線程模型 線程模型是Java的本質模型,它無所不在,所以Java開發必須搞清楚底層線程調度細節,不搞清楚當然就會有struts1,struts2的原理搞不清楚的基本災難(比如在struts2的action中塞入狀態,把struts2的action配成單例)。

用線程來抽象並發編程,是比較低級別的抽象,所以難度就大一些,難度級別會根據我們的任務特點有以下幾個類別 (1)任務非常獨立,不共享,這是最理想的情況,編程壓力為0。 (2)共享數據,壓力開始增大,必須引入鎖,Volatile變數,問題有活躍度和性能危險。

(3)狀態依賴,壓力再度增大,這時候我們基本上都是求助jdk 提供的同步工具。 五、任務執行 任務是一個抽象體,如果被抽象了出來,下一步就是交給編程平台去執行,在Java中,描述任務的一個基本介面是Runnable,可是這個抽象太有限了,它不能返回值和拋受檢查異常,所以Jdk5。

0有另外一個高級抽象Callable。 任務的執行在Jdk中也是一個底級別的Thread,線程有好處,但是大量線程就有大大的壞處,所以如果任務量很多我們並不能就創建大量的線程去服務這些任務,那麼Jdk5。

0在任務執行上做了抽象,將任務和任務執行隔離在介面背後,這樣我們就可以引入比如線程池的技術來優化執行,優化線程的創建。 任務是有生命周期的,所以Jdk5。

0提供了Future這個對象來描述對象的生命周期,通過這個future可以取到任務的結果甚至取消任務。 六、鎖 當然任務之間共享了數據,那麼要保證數據的安全,必須提供一個鎖機制來協調狀態,鎖讓數據訪問原子,但是引入了串列化,降低了並發度,鎖是降低程序伸縮性的原罪,鎖是引入上下文切換的主要原罪,鎖是引入死鎖,活鎖,優先順序倒置的絕對原罪,但是又不能沒有鎖,在Java中,鎖是一個對象,鎖提供原子和內存可見性,Volatile變數提供內存可見性不提供原子,原子變數提供可見性和原子,通過原子變數可以構建無鎖演算法和無鎖數據結構,但是這需要高高手才可以辦到。
5.Java高並發入門要怎麼學習
1、如果不使用框架,純原生Java編寫,是需要了解Java並發編程的,主要就是學習Doug Lea開發的那個java.util.concurrent包下面的API;2、如果使用框架,那麼我的理解,在代碼層面確實不會需要太多的去關注並發問題,反而是由於高並發會給系統造成很大壓力,要在緩存、資料庫操作上要多加考慮。

3、但是即使是使用框架,在工作中還是會用到多線程,就拿常見的CRUD介面來說,比如一個非常耗時的save介面,有多耗時呢?我們假設整個save執行完要10分鍾,所以,在save的時候,就需要採用非同步的方式,也就是單獨用一個線程去save,然後直接給前端返回200。
6.Java如何進行並發多連接socket編程呢
Java多個客戶端同時連接服務端,在現實生活中用得比較多。

同時執行多項任務,第一想到的當然是多線程了。下面用多線程來實現並發多連接。

import java。。

*; import java。io。

*; public class ThreadServer extends Thread { private Socket client; public ThreadServer(Socket c) { this。 client=c; } public void run() { try { BufferedReader in=new BufferedReader(new InputStreamReader(client。

getInputStream())); PrintWriter out=new PrintWriter(client。 getOutputStream()); Mutil User but can't parallel while (true) { String str=in。

readLine(); System。out。

println(str); out。 println("has receive。

"); out。

flush(); if (str。equals("end")) break; } client。

close(); } catch (IOException ex) { } finally { } } public static void main(String[] args)throws IOException { ServerSocket server=new ServerSocket(8000); while (true) { transfer location change Single User or Multi User ThreadServer mu=new ThreadServer(server。 accept()); mu。

start(); } } }J。
7.如何掌握java多線程,高並發,大數據方面的技能
線程:同一類線程共享代碼和數據空間,每個線程有獨立的運行棧和程序計數器(PC),線程切換開銷小。

(線程是cpu調度的最小單位)線程和進程一樣分為五個階段:創建、就緒、運行、阻塞、終止。多進程是指操作系統能同時運行多個任務(程序)。

多線程是指在同一程序中有多個順序流在執行。在java中要想實現多線程,有兩種手段,一種是繼續Thread類,另外一種是實現Runable介面.(其實准確來講,應該有三種,還有一種是實現Callable介面,並與Future、線程池結合使用。
8.java工程師需要掌握哪些知識
1.Core Java,就是Java基礎、JDK的類庫,很多童鞋都會說,JDK我懂,但是懂還不足夠,知其然還要知其所以然,JDK的源代碼寫的非常好,要經常查看,對使用頻繁的類,比如String, *** 類(List,Map,Set)等數據結構要知道它們的實現,不同的 *** 類有什麼區別,然後才能知道在一個具體的場合下使用哪個 *** 類更適合、更高效,這些內容直接看源代碼就OK了2.多線程並發編程,現在並發幾乎是寫服務端程序必須的技術,那對Java中的多線程就要有足夠的熟悉,包括對象鎖機制、synchronized關鍵字,concurrent包都要非常熟悉,這部分推薦你看看《Java並發編程實踐》這本書,講解的很詳細3.I/O,Socket編程,首先要熟悉Java中Socket編程,以及I/O包,再深入下去就是Java NIO,再深入下去是操作系統底層的Socket實現,了解Windows和Linux中是怎麼實現socket的4.JVM的一些知識,不需要熟悉,但是需要了解,這是Java的本質,可以說是Java的母體, 了解之後眼界會更寬闊,比如Java內存模型(會對理解Java鎖、多線程有幫助)、位元組碼、JVM的模型、各種垃圾收集器以及選擇、JVM的執行參數(優化JVM)等等,這些知識在《深入Java虛擬機》這本書中都有詳盡的解釋,或者去oracle網站上查看具體版本的JVM規范.5.一些常用的設計模式,比如單例、模板方法、代理、適配器等等,以及在Core Java和一些Java框架里的具體場景的實現,這個可能需要慢慢積累,先了解有哪些使用場景,見得多了,自己就自然而然會去用。

6.常用資料庫(Oracle、MySQL等)、SQL語句以及一般的優化7.JavaWeb開發的框架,比如Spring、iBatis等框架,同樣他們的原理才是最重要的,至少要知道他們的大致原理。8.其他一些有名的用的比較多的開源框架和包,ty網路框架,Apache mon的N多包,Google的Guava等等,也可以經常去Github上找一些代碼看看。

暫時想到的就這么多吧,1-4條是Java基礎,全部的這些知識沒有一定的時間積累是很難搞懂的,但是了解了之後會對Java有個徹底的了解,5和6是需要學習的額外技術,7-8是都是基於1-4條的,正所謂萬變不離其宗,前4條就是Java的靈魂所在,希望能對你有所幫助9.(補充)學會使用Git。如果你還在用SVN的話,趕緊投入Git的懷抱吧。
9.java 多線程的並發到底是什麼意思
一、多線程1、操作系統有兩個容易混淆的概念,進程和線程。

進程:一個計算機程序的運行實例,包含了需要執行的指令;有自己的獨立地址空間,包含程序內容和數據;不同進程的地址空間是互相隔離的;進程擁有各種資源和狀態信息,包括打開的文件、子進程和信號處理。線程:表示程序的執行流程,是CPU調度執行的基本單位;線程有自己的程序計數器、寄存器、堆棧和幀。

同一進程中的線程共用相同的地址空間,同時共享進進程鎖擁有的內存和其他資源。2、Java標准庫提供了進程和線程相關的API,進程主要包括表示進程的java.lang.Process類和創建進程的java.lang.ProcessBuilder類;表示線程的是java.lang.Thread類,在虛擬機啟動之後,通常只有Java類的main方法這個普通線程運行,運行時可以創建和啟動新的線程;還有一類守護線程(damon thread),守護線程在後台運行,提供程序運行時所需的服務。

當虛擬機中運行的所有線程都是守護線程時,虛擬機終止運行。3、線程間的可見性:一個線程對進程 *** 享的數據的修改,是否對另一個線程可見可見性問題:a、CPU採用時間片輪轉等不同演算法來對線程進行調度[java] view plainpublic class IdGenerator{ private int value = 0; public int getNext(){ return value++; } } 對於IdGenerator的getNext()方法,在多線程下不能保證返回值是不重復的:各個線程之間相互競爭CPU時間來獲取運行機會,CPU切換可能發生在執行間隙。

以上代碼getNext()的指令序列:CPU切換可能發生在7條指令之間,多個getNext的指令交織在一起。

5. 「高並發」兩種非同步模型與深度解析Future介面-

大家好,我是冰河~~

本文有點長,但是滿滿的干貨,以實際案例的形式分析了兩種非同步模型,並從源碼角度深度解析Future介面和FutureTask類,希望大家踏下心來,打開你的IDE,跟著文章看源碼,相信你一定收獲不小!

在Java的並發編程中,大體上會分為兩種非同步編程模型,一類是直接以非同步的形式來並行運行其他的任務,不需要返回任務的結果數據。一類是以非同步的形式運行其他任務,需要返回結果。

1.無返回結果的非同步模型

無返回結果的非同步任務,可以直接將任務丟進線程或線程池中運行,此時,無法直接獲得任務的執行結果數據,一種方式是可以使用回調方法來獲取任務的運行結果。

具體的方案是:定義一個回調介面,並在介面中定義接收任務結果數據的方法,具體邏輯在回調介面的實現類中完成。將回調介面與任務參數一同放進線程或線程池中運行,任務運行後調用介面方法,執行回調介面實現類中的邏輯來處理結果數據。這里,給出一個簡單的示例供參考。

便於介面的通用型,這里為回調介面定義了泛型。

回調介面的實現類主要用來對任務的返回結果進行相應的業務處理,這里,為了方便演示,只是將結果數據返回。大家需要根據具體的業務場景來做相應的分析和處理。

任務的執行類是具體執行任務的類,實現Runnable介面,在此類中定義一個回調介面類型的成員變數和一個String類型的任務參數(模擬任務的參數),並在構造方法中注入回調介面和任務參數。在run方法中執行任務,任務完成後將任務的結果數據封裝成TaskResult對象,調用回調介面的方法將TaskResult對象傳遞到回調方法中。

到這里,整個大的框架算是完成了,接下來,就是測試看能否獲取到非同步任務的結果了。

在測試類中,使用Thread類創建一個新的線程,並啟動線程運行任務。運行程序最終的介面數據如下所示。

大家可以細細品味下這種獲取非同步結果的方式。這里,只是簡單的使用了Thread類來創建並啟動線程,也可以使用線程池的方式實現。大家可自行實現以線程池的方式通過回調介面獲取非同步結果。

2.有返回結果的非同步模型

盡管使用回調介面能夠獲取非同步任務的結果,但是這種方式使用起來略顯復雜。在JDK中提供了可以直接返回非同步結果的處理方案。最常用的就是使用Future介面或者其實現類FutureTask來接收任務的返回結果。

使用Future介面往往配合線程池來獲取非同步執行結果,如下所示。

運行結果如下所示。

FutureTask類既可以結合Thread類使用也可以結合線程池使用,接下來,就看下這兩種使用方式。

結合Thread類的使用示例如下所示。

運行結果如下所示。

結合線程池的使用示例如下。

運行結果如下所示。

可以看到使用Future介面或者FutureTask類來獲取非同步結果比使用回調介面獲取非同步結果簡單多了。注意:實現非同步的方式很多,這里只是用多線程舉例。

接下來,就深入分析下Future介面。

1.Future介面

Future是JDK1.5新增的非同步編程介面,其源代碼如下所示。

可以看到,在Future介面中,總共定義了5個抽象方法。接下來,就分別介紹下這5個方法的含義。

取消任務的執行,接收一個boolean類型的參數,成功取消任務,則返回true,否則返回false。當任務已經完成,已經結束或者因其他原因不能取消時,方法會返回false,表示任務取消失敗。當任務未啟動調用了此方法,並且結果返回true(取消成功),則當前任務不再運行。如果任務已經啟動,會根據當前傳遞的boolean類型的參數來決定是否中斷當前運行的線程來取消當前運行的任務。

判斷任務在完成之前是否被取消,如果在任務完成之前被取消,則返回true;否則,返回false。

這里需要注意一個細節:只有任務未啟動,或者在完成之前被取消,才會返回true,表示任務已經被成功取消。其他情況都會返回false。

判斷任務是否已經完成,如果任務正常結束、拋出異常退出、被取消,都會返回true,表示任務已經完成。

當任務完成時,直接返回任務的結果數據;當任務未完成時,等待任務完成並返回任務的結果數據。

當任務完成時,直接返回任務的結果數據;當任務未完成時,等待任務完成,並設置了超時等待時間。在超時時間內任務完成,則返回結果;否則,拋出TimeoutException異常。

2.RunnableFuture介面

Future介面有一個重要的子介面,那就是RunnableFuture介面,RunnableFuture介面不但繼承了Future介面,而且繼承了java.lang.Runnable介面,其源代碼如下所示。

這里,問一下,RunnableFuture介面中有幾個抽象方法?想好了再說!哈哈哈。。。

這個介面比較簡單run()方法就是運行任務時調用的方法。

3.FutureTask類

FutureTask類是RunnableFuture介面的一個非常重要的實現類,它實現了RunnableFuture介面、Future介面和Runnable介面的所有方法。FutureTask類的源代碼比較多,這個就不粘貼了,大家自行到java.util.concurrent下查看。

(1)FutureTask類中的變數與常量

在FutureTask類中首先定義了一個狀態變數state,這個變數使用了volatile關鍵字修飾,這里,大家只需要知道volatile關鍵字通過內存屏障和禁止重排序優化來實現線程安全,後續會單獨深度分析volatile關鍵字是如何保證線程安全的。緊接著,定義了幾個任務運行時的狀態常量,如下所示。

其中,代碼注釋中給出了幾個可能的狀態變更流程,如下所示。

接下來,定義了其他幾個成員變數,如下所示。

又看到我們所熟悉的Callable介面了,Callable介面那肯定就是用來調用call()方法執行具體任務了。

看一下WaitNode類的定義,如下所示。

可以看到,WaitNode類是FutureTask類的靜態內部類,類中定義了一個Thread成員變數和指向下一個WaitNode節點的引用。其中通過構造方法將thread變數設置為當前線程。

(2)構造方法

接下來,是FutureTask的兩個構造方法,比較簡單,如下所示。

(3)是否取消與完成方法

繼續向下看源碼,看到一個任務是否取消的方法,和一個任務是否完成的方法,如下所示。

這兩方法中,都是通過判斷任務的狀態來判定任務是否已取消和已完成的。為啥會這樣判斷呢?再次查看FutureTask類中定義的狀態常量發現,其常量的定義是有規律的,並不是隨意定義的。其中,大於或者等於CANCELLED的常量為CANCELLED、INTERRUPTING和INTERRUPTED,這三個狀態均可以表示線程已經被取消。當狀態不等於NEW時,可以表示任務已經完成。

通過這里,大家可以學到一點:以後在編碼過程中,要按照規律來定義自己使用的狀態,尤其是涉及到業務中有頻繁的狀態變更的操作,有規律的狀態可使業務處理變得事半功倍,這也是通過看別人的源碼設計能夠學到的,這里,建議大家還是多看別人寫的優秀的開源框架的源碼。

(4)取消方法

我們繼續向下看源碼,接下來,看到的是cancel(boolean)方法,如下所示。

接下來,拆解cancel(boolean)方法。在cancel(boolean)方法中,首先判斷任務的狀態和CAS的操作結果,如果任務的狀態不等於NEW或者CAS的操作返回false,則直接返回false,表示任務取消失敗。如下所示。

接下來,在try代碼塊中,首先判斷是否可以中斷當前任務所在的線程來取消任務的運行。如果可以中斷當前任務所在的線程,則以一個Thread臨時變數來指向運行任務的線程,當指向的變數不為空時,調用線程對象的interrupt()方法來中斷線程的運行,最後將線程標記為被中斷的狀態。如下所示。

這里,發現變更任務狀態使用的是UNSAFE.putOrderedInt()方法,這個方法是個什麼鬼呢?點進去看一下,如下所示。

可以看到,又是一個本地方法,嘿嘿,這里先不管它,後續文章會詳解這些方法的作用。

接下來,cancel(boolean)方法會進入finally代碼塊,如下所示。

可以看到在finallly代碼塊中調用了finishCompletion()方法,顧名思義,finishCompletion()方法表示結束任務的運行,接下來看看它是如何實現的。點到finishCompletion()方法中看一下,如下所示。

在finishCompletion()方法中,首先定義一個for循環,循環終止因子為waiters為null,在循環中,判斷CAS操作是否成功,如果成功進行if條件中的邏輯。首先,定義一個for自旋循環,在自旋循環體中,喚醒WaitNode堆棧中的線程,使其運行完成。當WaitNode堆棧中的線程運行完成後,通過break退出外層for循環。接下來調用done()方法。done()方法又是個什麼鬼呢?點進去看一下,如下所示。

可以看到,done()方法是一個空的方法體,交由子類來實現具體的業務邏輯。

當我們的具體業務中,需要在取消任務時,執行一些額外的業務邏輯,可以在子類中覆寫done()方法的實現。

(5)get()方法

繼續向下看FutureTask類的代碼,FutureTask類中實現了兩個get()方法,如下所示。

沒參數的get()方法為當任務未運行完成時,會阻塞,直到返回任務結果。有參數的get()方法為當任務未運行完成,並且等待時間超出了超時時間,會TimeoutException異常。

兩個get()方法的主要邏輯差不多,一個沒有超時設置,一個有超時設置,這里說一下主要邏輯。判斷任務的當前狀態是否小於或者等於COMPLETING,也就是說,任務是NEW狀態或者COMPLETING,調用awaitDone()方法,看下awaitDone()方法的實現,如下所示。

接下來,拆解awaitDone()方法。在awaitDone()方法中,最重要的就是for自旋循環,在循環中首先判斷當前線程是否被中斷,如果已經被中斷,則調用removeWaiter()將當前線程從堆棧中移除,並且拋出InterruptedException異常,如下所示。

接下來,判斷任務的當前狀態是否完成,如果完成,並且堆棧句柄不為空,則將堆棧中的當前線程設置為空,返回當前任務的狀態,如下所示。

當任務的狀態為COMPLETING時,使當前線程讓出CPU資源,如下所示。

如果堆棧為空,則創建堆棧對象,如下所示。

如果queued變數為false,通過CAS操作為queued賦值,如果awaitDone()方法傳遞的timed參數為true,則計算超時時間,當時間已超時,則在堆棧中移除當前線程並返回任務狀態,如下所示。如果未超時,則重置超時時間,如下所示。

如果不滿足上述的所有條件,則將當前線程設置為等待狀態,如下所示。

接下來,回到get()方法中,當awaitDone()方法返回結果,或者任務的狀態不滿足條件時,都會調用report()方法,並將當前任務的狀態傳遞到report()方法中,並返回結果,如下所示。

看來,這里還要看下report()方法啊,點進去看下report()方法的實現,如下所示。

可以看到,report()方法的實現比較簡單,首先,將outcome數據賦值給x變數,接下來,主要是判斷接收到的任務狀態,如果狀態為NORMAL,則將x強轉為泛型類型返回;當任務的狀態大於或者等於CANCELLED,也就是任務已經取消,則拋出CancellationException異常,其他情況則拋出ExecutionException異常。

至此,get()方法分析完成。注意:一定要理解get()方法的實現,因為get()方法是我們使用Future介面和FutureTask類時,使用的比較頻繁的一個方法。

(6)set()方法與setException()方法

繼續看FutureTask類的代碼,接下來看到的是set()方法與setException()方法,如下所示。

通過源碼可以看出,set()方法與setException()方法整體邏輯幾乎一樣,只是在設置任務狀態時一個將狀態設置為NORMAL,一個將狀態設置為EXCEPTIONAL。

至於finishCompletion()方法,前面已經分析過。

(7)run()方法與runAndReset()方法

接下來,就是run()方法了,run()方法的源代碼如下所示。

可以這么說,只要使用了Future和FutureTask,就必然會調用run()方法來運行任務,掌握run()方法的流程是非常有必要的。在run()方法中,如果當前狀態不是NEW,或者CAS操作返回的結果為false,則直接返回,不再執行後續邏輯,如下所示。

接下來,在try代碼塊中,將成員變數callable賦值給一個臨時變數c,判斷臨時變數不等於null,並且任務狀態為NEW,則調用Callable介面的call()方法,並接收結果數據。並將ran變數設置為true。當程序拋出異常時,將接收結果的變數設置為null,ran變數設置為false,並且調用setException()方法將任務的狀態設置為EXCEPTIONA。接下來,如果ran變數為true,則調用set()方法,如下所示。

接下來,程序會進入finally代碼塊中,如下所示。

這里,將runner設置為null,如果任務的當前狀態大於或者等於INTERRUPTING,也就是線程被中斷了。則調用()方法,接下來,看下()方法的實現。

可以看到,()方法的實現比較簡單,當任務的狀態為INTERRUPTING時,使用while()循環,條件為當前任務狀態為INTERRUPTING,將當前線程佔用的CPU資源釋放,也就是說,當任務運行完成後,釋放線程所佔用的資源。

runAndReset()方法的邏輯與run()差不多,只是runAndReset()方法會在finally代碼塊中將任務狀態重置為NEW。runAndReset()方法的源代碼如下所示,就不重復說明了。

(8)removeWaiter()方法

removeWaiter()方法中主要是使用自旋循環的方式來移除WaitNode中的線程,比較簡單,如下所示。

最後,在FutureTask類的最後,有如下代碼。

關於這些代碼的作用,會在後續深度解析CAS文章中詳細說明,這里就不再探討。

至此,關於Future介面和FutureTask類的源碼就分析完了。

好了,今天就到這兒吧,我是冰河,我們下期見~~

熱點內容
客戶端反編譯教學 發布:2024-10-06 07:10:42 瀏覽:782
阿里雲香港伺服器被牆 發布:2024-10-06 06:45:46 瀏覽:229
標簽匹配演算法 發布:2024-10-06 06:37:23 瀏覽:221
雲頂之弈腳本 發布:2024-10-06 06:37:23 瀏覽:765
jsp與javaweb 發布:2024-10-06 06:32:13 瀏覽:295
c語言修飾符 發布:2024-10-06 06:27:09 瀏覽:276
有解壓密碼的壓縮包 發布:2024-10-06 06:18:46 瀏覽:72
分鏡頭腳本模板廣告 發布:2024-10-06 06:18:44 瀏覽:14
大眾邁騰車輛密碼在哪裡 發布:2024-10-06 06:05:51 瀏覽:673
access資料庫亂碼 發布:2024-10-06 06:05:18 瀏覽:322