基礎知識。執行緒是cpu排程的最小單元。乙個執行緒可以看作是在執行乙個任務。除建立和銷毀,執行緒的生命週期還包括就緒、執行、阻塞。
cpu是按時間片來執行任務的,多個執行緒都有機會獲得時間片,這樣多個任務就可以併發地執行。執行緒間的切換會涉及到上下文儲存的開銷。由於執行緒間共享程序內的資料資源,故執行緒切換的開銷比程序切換的開銷要小很多。在大多數通用的處理器中,上下文切換的開銷相當於5000到10000個時鐘週期。
因為大多時候乙個執行緒不可能滿負荷地占用cpu,會有一些io或介面呼叫的操作,這個時候cpu是空閒的,就可以切換別的執行緒執行,從而大大地提高效率和併發量。
建立並啟動多個執行緒就可以實現多執行緒,你大致可以通過以下三種方式:
new thread(runnable).start();
executorservice.execute(runnable);
future<?> = executorservice.submit(callable<?>);
如何獲得executorservice,如下。區別很明顯,具體含義參見api。
executors.newsinglethreadexecutor();
executors.newcachedthreadpool();
executors.newfixedthreadpool(nthreads);
executors.newscheduledthreadpool(corepoolsize);
除了簡單的建立並啟動,你還可以通過scheduledexecutorservice來排程你的執行緒,你可以讓執行緒等待多長時間啟動,並多久迴圈,使用很簡單,具體參見api。
除執行緒切換開銷外,最大的問題就是多個執行緒競爭共享資源時,可能會破壞共享資源,因為很多操作都不是原子的。比如a正在寫共享資源g,可能還未寫完b就來讀,得到不正確的g;可能b讀完還要寫入,導致g被破壞。即使能保證共享資源不被破壞,也可能根據共享狀態作判斷的時候取不到正確時機的狀態而判斷錯誤。比如a在時刻1取到共享狀態g為true,當執行過程中可能g被b修改為了false,a後續依賴b為true的操作將是錯誤的。
為了解決執行緒安全,程式設計會變得複雜,同時避免不了對共享資源進行鎖定,這樣阻塞會更頻繁,可能還會死鎖。死鎖的四個必要條件:互斥、持有並等待、非搶占式、迴圈等待。
總之,多執行緒會給你帶來莫名其妙的問題,狀態出錯、資料出錯、或者偶爾的效能下降。
1. 執行緒內部的資源是執行緒安全的。
2. 唯讀資源是執行緒安全的。
3. 對共享資源操作方法或**塊使用同步synchronized,保證同一時刻只有乙個執行緒訪問共享資源,是執行緒安全的。
4. 當乙個執行緒將對共享資源進行寫操作時或者後續操作依賴讀操作的結果時,先獲取資源的鎖(trylock),對資源進行鎖定,操作完後釋放鎖,可以保證執行緒安全。
逐步從以下幾個方面去考慮:
1. 是否一定要使用多執行緒,是否一定要共享資源。
2. 避免熱點域成為共享的競爭資源。
3. 避免使用獨佔鎖,尋找可行的替代方式,如依賴concurrent包中的資料結構(最好了解其實現),採用讀寫鎖等。
4. 避免對大段操作加鎖,縮小鎖的範圍,快進快出。
5. 避免對大量資料加鎖,減少鎖的粒度,進行分拆和分離。
6. 監控cpu利用率、記憶體占有和釋放情況(gc)來進行分析。
文章首發於:www.newhottopic.com
java 多執行緒程式設計記錄
為了避免主線程退出導致其它還未執行完的執行緒退出,可以使用executorservice管理多執行緒的生命週期 executorservice exec executors.newcachedthreadpool for int i 0 i 100 i exec.shutdown 關於類的靜態和非靜...
Java多執行緒程式設計基礎2
一 執行緒的生命週期 新建 new 就緒 runnable 執行 running 阻塞 blocked 死亡 dead 執行緒類有以下成員函式 1.void start 啟動執行緒 2.void join 等待被join的執行緒執行完成 3.void join long millis 等待被join...
java中的多執行緒程式設計
一 當兩個併發執行緒訪問同乙個物件object中的這個synchronized this 同步 塊時,乙個時間內只能有乙個執行緒得到執行。另乙個執行緒必須等待當前執行緒執行完這個 塊以後才能執行該 塊。package ths public class thread1 implements runna...