Java-并發(fā)編程培訓_第1頁
Java-并發(fā)編程培訓_第2頁
Java-并發(fā)編程培訓_第3頁
Java-并發(fā)編程培訓_第4頁
Java-并發(fā)編程培訓_第5頁
已閱讀5頁,還剩81頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

Java_并發(fā)編程培訓第一頁,共86頁。在一個list中有過億條的Integer類型的值,如何更快的計算這些值的總和?一個計算的問題簡單的方法:更快的CPU來遍歷靠譜的方法:分而治之來處理進一步的方法:Fork/jion第二頁,共86頁。簡單的方法靠譜么?免費午餐已經(jīng)結束——軟件歷史性地向并發(fā)靠攏軟層次上:遍歷是不靠譜的,for小學生了!第三頁,共86頁。靠譜的方法簡單么?(分而治之)list1list2list3ConcurrencyThreadThreadThread那幫Java大神在他們書中說:

在對性能的追求很可能是并發(fā)bug唯一最大的來源!So:

同樣不是免費的午餐,需要學習和批量實踐。第四頁,共86頁。目錄線程并發(fā)編程(juc)線程監(jiān)控工具編程思想和實踐

Fork/Jion框架第五頁,共86頁。Visibility:通過并發(fā)線程修改變量值,必須將線程變量同步回主存后,其他線程才能訪問到。Ordering:通過java提供的同步機制或volatile關鍵字,來保證內存的訪問順序。Cachecoherency:它是一種管理多處理器系統(tǒng)的高速緩存區(qū)結構,其可以保證數(shù)據(jù)在高速緩存區(qū)到內存的傳輸中不會丟失或重復。Happens-beforeordering:synchronized,volatile,final,java.util.concurrent.lock|atomic線程:先讓路給內存模型這里有詳述:(別迷戀哥,哥只是傳說!)第六頁,共86頁。內存中的可見部分Stack-1Stack-2Stack-3GlobalsHeap第七頁,共86頁。線程:synchronized內部鎖分離鎖分拆鎖保證原子性和可見性第八頁,共86頁。線程:JavaMonitorsThisfigureshowsthemonitorasthreerectangles.Inthecenter,alargerectanglecontainsasinglethread,themonitor'sowner.Ontheleft,asmallrectanglecontainstheentryset.Ontheright,anothersmallrectanglecontainsthewaitset.Activethreadsareshownasdarkgraycircles.Suspendedthreadsareshownaslightgraycircles.第九頁,共86頁。線程:獨占鎖(synchronized)非方法修飾符,注意方法覆寫的時候需要加上synchronized;經(jīng)典的順序鎖問題(兩個線程安全的方法放在一起線程安全么?)getClass的問題?!谑?,共86頁。分拆前:思考問題,順便教你一招!分拆不了人,工具還不能分拆么?對,買3個手機去……第十一頁,共86頁。線程:分拆鎖第十二頁,共86頁。線程:分離鎖分離鎖負面作用:對容器加鎖,進行獨占訪問更加困難,并且更加昂貴了。內存使用的問題:sina就曾經(jīng)因為在Action層使用ConcurrentHashMap而導致內存使用過大,修改array后竟然單臺服務器節(jié)省2G。第十三頁,共86頁。線程:static的案例publicclassStaticThreadTest{ //線程避免調用這個;

publicstaticTreetree=newTree(“jizi”,“2”); publicstaticvoidcreateTree(Treetrees){ Treet=tree; if(trees.getName().equals("pg")){t.setName("ceshi");} } publicstaticvoidmain(String[]args)throws InterruptedException{ ExecutorServiceexec= Executors.newFixedThreadPool(10); for(inti=0;i<10;i++){ exec.execute(newTreeThread(i)); Thread.sleep(50); } exec.shutdown(); exec.awaitTermination(1,TimeUnit.SECONDS); }}第十四頁,共86頁。線程:可見性volatile關鍵字:1:簡化實現(xiàn)或者同步策略驗證的時候來使用它;2:確保引用對象的可見性;3:標示重要的生命周期的事件,例如:開始或者關閉。脆弱的volatile的使用條件:1:寫入變量不依賴變量的當前值,或者能夠保證只有單一的線程修改變量的值;2:變量不需要和其他變量共同參與不變約束;3:訪問變量時不需要其他原因需要加鎖。privatevolatilebooleanisInterrupted=false;第十五頁,共86頁。任務的取消和線程超時第十六頁,共86頁。線程中斷第十七頁,共86頁。教父JoshuaBloch說線程:對共享可變數(shù)據(jù)同步訪問;避免過多的同步;永遠不要在循環(huán)外面調用wait;不要依賴于線程調度器;線程安全的文檔化;避免使用線程組。第十八頁,共86頁。目錄線程并發(fā)編程(juc)線程監(jiān)控工具編程思想和實踐

Fork/Jion框架第十九頁,共86頁。開始并發(fā)編程了第二十頁,共86頁。行動之前,拜神先Mr.concurrency,當今世界上并發(fā)程序設計領域的先驅,著名學者。他是util.concurrent包的作者,JSR166規(guī)范的制定。圖書著作《ConcurrentProgramminginJava:DesignPrinciplesandPatterns》。其”AScalableElimination-basedExchangeChannel”和”ScalableSynchronousQueues”兩篇論文列為非阻塞同步算法的經(jīng)典文章。Afork/jionframework同樣影響著java7。DougLea第二十一頁,共86頁。Amdahl定律并發(fā)編程:三大定律(1)討論的是加速比(speedup)的問題第二十二頁,共86頁。Gustafson定律并發(fā)編程:三大定律(2)Gustafson假設隨著處理器個數(shù)的增加,并行與串行的計算總量也是可以增加的。Gustafson定律認為加速系數(shù)幾乎跟處理器個數(shù)成正比,如果現(xiàn)實情況符合Gustafson定律的假設前提的話,那么軟件的性能將可以隨著處理個數(shù)的增加而增加。第二十三頁,共86頁。Sun-Ni定律并發(fā)編程:三大定律(3)充分利用存儲空間等計算資源,盡量增大問題規(guī)模以產生更好/更精確的解。第二十四頁,共86頁。總結不是API,是寂寞!第二十五頁,共86頁。來個高清無碼版ExecutorsExecutorExecutorServiceScheduledExecutorServiceCallableFutureScheduledFutureDelayedCompletionServiceThreadPoolExecutorScheduledThreadPoolExecutorAbstractExecutorServiceExecutorsFutureTaskExecutorCompletionServiceQueuesBlockingQueueConcurrentLinkedQueueLinkedBlockingQueueArrayBlockingQueueSynchronousQueuePriorityBlockingQueueDelayQueueConcurrentCollectionsConcurrentMapConcurrentHashMapCopyOnWriteArray{List,Set}SynchronizersCountDownLatchSemaphoreExchangerCyclicBarrierTimingTimeUnitLocksLockConditionReadWriteLockAbstractQueuedSynchronizerLockSupportReentrantLockReentrantReadWriteLockAtomicsAtomic[Type],Atomic[Type]ArrayAtomic[Type]FieldUpdaterAtomic{Markable,Stampable}Reference第二十六頁,共86頁。ThreadPoolExecutor:自己動手,豐衣足食!

publicstaticExecutorServicenewFixedThreadPool(intnThreads){

returnnewThreadPoolExecutor(nThreads,nThreads,0L,TimeUnit.MILLISECONDS,

newLinkedBlockingQueue<Runnable>());

}1:線程池的大小最好是設定好,因為JDK的管理內存畢竟是有限的;2:使用結束,需要關閉線程池;3:Runtime.getRuntime().addShutdownHook(hook);對不能正常關閉的線程做好相關的記錄。第二十七頁,共86頁。Executors:ExecutorService嚴重注意:別設置線程池無限大小第二十八頁,共86頁。入門版:CompletionService生產者消費者模式的簡要實現(xiàn)版本。第二十九頁,共86頁。雙劍合璧:Future+Callable第三十頁,共86頁。任務池:ScheduledExecutorService計劃任務執(zhí)行相關的操作,使用java真幸福,選擇多多!第三十一頁,共86頁。阻塞隊列:BlockingQueue拋出異常特殊值阻塞超時插入add(e)offer(e)put(e)offer(e,time,unit)移除remove()poll()take()poll(time,unit)檢查element()peek()不可用不可用Kaopuability:插入(offer);移除(poll)第三十二頁,共86頁。BlockingQueue的諸侯領地ArrayBlockingQueue:一個由數(shù)組支持的有界阻塞隊列。此隊列按FIFO(先進先出)原則對元素進行排序。Delayed元素的一個無界阻塞隊列,只有在延遲期滿時才能從中提取元素.LinkedBlockingDeque一個基于已鏈接節(jié)點的、任選范圍的阻塞雙端隊列。LinkedBlockingQueue一個基于已鏈接節(jié)點的、范圍任意的blockingqueue。此隊列按FIFO(先進先出)排序元素PriorityBlockingQueue一個無界阻塞隊列,它使用與類PriorityQueue相同的順序規(guī)則,并且提供了阻塞獲取操作。SynchronousQueue一種阻塞隊列,其中每個插入操作必須等待另一個線程的對應移除操作,反之亦然。第三十三頁,共86頁。BlockingDeque:雙端隊列第一個元素(頭部)拋出異常特殊值阻塞超時期插入addFirst(e)offerFirst(e)putFirst(e)offerFirst(e,time,unit)移除removeFirst()pollFirst()takeFirst()pollFirst(time,unit)檢查getFirst()peekFirst()不適用不適用最后一個元素(尾部)拋出異常特殊值阻塞超時期插入addLast(e)offerLast(e)putLast(e)offerLast(e,time,unit)移除removeLast()pollLast()takeLast()pollLast(time,unit)檢查getLast()peekLast()不適用不適用第三十四頁,共86頁。并發(fā)集合:你值得擁有同步的不是Map,是鳳姐!第三十五頁,共86頁。ConcurrentHashMap:解放軍38軍你那飄逸的同步,分離鎖的設計,再hash算法以及游離于多個Segment的耍心跳的各種操作,都深深的吸引了我。詳細設計細節(jié):第三十六頁,共86頁。比較Map的性能第三十七頁,共86頁。CopyOnWriteArray{List,Set}當讀操作遠遠大于寫操作的時候,考慮用這個并發(fā)集合。例如:維護監(jiān)聽器的集合。注意:其頻繁寫的效率可能低的驚人。奇技淫巧:屏蔽add帶來的數(shù)組拷貝;publicList<String>array=newArrayList<String>();publicList<String>list=newCopyOnWriteArrayList<String>(array);第三十八頁,共86頁。同步器:四大金剛第三十九頁,共86頁。閉鎖:CountDownLatch等待啟動信號線程A獲得等待啟動信號線程B獲得等待啟動信號線程C獲得等待啟動信號線程A運行,遞減鎖存器的計數(shù)線程B運行,遞減鎖存器的計數(shù)線程C運行,遞減鎖存器的計數(shù)等待完成信號繼續(xù)啟動信號+完成信號的模式N部分鎖存器倒計數(shù)模式;當線程必須用這種方法反復倒計數(shù)時,可改為使用CyclicBarrier典型應用:手動控制事務,從數(shù)據(jù)庫讀取多份數(shù)據(jù)做初始化;第四十頁,共86頁。關卡:CyclicBarrierBarrierABCABCBarrierBarrierABCAbarrier:Abarrierisacoordinationmechanosm(analgorithm)thatforcesprocesswhichparticipateinaconcurrent(ordistributed)algorithmtowaituntileachoneofthemhasreachedacertainpointinitsprogram.Thecollectionofthesecoordinationpointsiscalledthebarrier.Oncealltheprocesseshavereachedthebarrier,theyareallpermittedtocontinuepastthebarrier.第四十一頁,共86頁。信號量:Semaphore獲取信號(acquire();)第四十二頁,共86頁。交換器:Exchanger數(shù)據(jù)分解和數(shù)據(jù)流分解的一種技巧,可被視為SynchronousQueue的雙向形式。JDK5時支持2個線程之間交換數(shù)據(jù),JDK6后支持多個。至今我沒有用過第四十三頁,共86頁。鎖云:你的柔情我永遠不懂內部鎖互斥鎖分離鎖分拆鎖閉鎖獨占鎖讀寫鎖順序鎖第四十四頁,共86頁?;コ怄i:ReentrantLockLock更加靈活,性能更好

interfaceLock{ voidlock(); voidlockInterruptibly()throwsInterruptedException; booleantryLock(); booleantryLock(longtimeout,TimeUnitunit) throwsInterruptedException; voidunlock(); ConditionnewCondition(); }支持多個Condition可以不以代碼塊的方式上鎖可以使用tryLock,并指定等待上鎖的超時時間調試時可以看到內部的ownerthread,方便排除死鎖RenntrantLock支持fair和unfair兩種模式第四十五頁,共86頁?;コ怄i(公平與非公平)和內部鎖性能對比圖結論:非公平互斥鎖和內部鎖性能在jdk6_17下性能基本一樣。測試機:酷睿2.66雙核,2G內存,win7第四十六頁,共86頁。讀寫鎖:ReadWriteLockReadWriteLock維護了一對相關的鎖,一個用于只讀操作,另一個用于寫入操作。只要沒有writer,讀取鎖可以由多個reader線程同時保持。寫入鎖是獨占的。ReentrantReadWriteLockReadLockWriteLock線程1線程2線程3第四十七頁,共86頁。高深:AbstractQueuedSynchronizer為實現(xiàn)依賴于先進先出(FIFO)等待隊列的阻塞鎖和相關同步器(信號量、事件,等等)提供一個框架;基于JDK底層來操控線程調度,LockSupport.park和LockSupport.unpark;此類支持默認的獨占模式和共享模式之一,或者二者都支持;如果想玩玩它,請看CountDownLatch的源碼。當然,也可以去FutureTask這個類看看。第四十八頁,共86頁。目錄線程并發(fā)編程(juc)線程監(jiān)控工具編程思想和實踐

Fork/Jion框架第四十九頁,共86頁。Fork/JoinFramework(1)WorkStealing第五十頁,共86頁。Fork/JoinFrameworkFJTask框架是Cilk用到的設計方案的變體,相關系統(tǒng)依賴于輕量級可執(zhí)行任務。這些框架都是像操作系統(tǒng)映射線程到CPU一樣來映射任務到線程,從而開發(fā)單純,有規(guī)律,有約束力的fork/join程序來執(zhí)行映射動作。工作線程池是確定的,每個工作線程(Thread子類FJTaskRunner的一個實例)是處理隊列中任務的標準線程。正常的,工作線程的數(shù)量和系統(tǒng)的CPU的數(shù)量是一致的。任何合乎情理的映射策略將把這些線程映射到不同的cpu。所有的fork/join任務都是一個輕量級可執(zhí)行類的實例,不是一個線程實例。在java中,獨立的可執(zhí)行任務必須實現(xiàn)Runnable接口并定義一個run()方法。在FJTask框架中,這些任務是FJTask的子類而不是Thread的子類,它們都實現(xiàn)了Runnable接口一個簡單的控制和管理設施(這里講的是FJTaskRunnerGroup)設置工作池,從一個正常的線程(例如java語言中的main()方法)調用啟動執(zhí)行提供的fork/join任務。DougLea論文:第五十一頁,共86頁。Fork/Join的案例:求數(shù)組中的最大值第五十二頁,共86頁。Fork/Join運行測試結果

闕值=500k闕值=50k闕值=5k闕值=500闕值=-50Pentium-4HT(2個線程)1.01.071.02.82.2Dual-XeonHT(4個線程).883.038-wayOpteron(8個線程)1.05.295.734.532.038-coreNiagara(32個線程).9810.4617.2115.346.49表1.在不同系統(tǒng)上從500k個元素的數(shù)組中運行select-max的結果

fork-join池中的線程數(shù)量與可用的硬件線程(內核數(shù)乘以每個內核中的線程數(shù))相等第五十三頁,共86頁。Fork/Join有用的資源表1.在不同系統(tǒng)上從500k個元素的數(shù)組中運行select-max的結果

jsr166:Java理論與實踐:

應用fork-join框架:BrianGoetzJDK7中的Fork/Join模式第五十四頁,共86頁。目錄線程并發(fā)編程(juc)線程監(jiān)控工具編程思想和實踐

Fork/Jion框架第五十五頁,共86頁。線程監(jiān)控:DIYWindows下面DIY方式很多,txt編輯器都是好東西第五十六頁,共86頁。線程監(jiān)控:Jconsole第五十七頁,共86頁。線程監(jiān)控:VisualVm本地下載地址:JDK1.6之后自帶了這個攻擊,在java_home/bin下面;喜新厭舊的GGDDJJMM去上述地址下載吧!第五十八頁,共86頁。內存監(jiān)控:VisualVm遠程第五十九頁,共86頁。ThreadDumpAnalyzer第六十頁,共86頁。目錄線程并發(fā)編程(juc)線程監(jiān)控工具編程思想和實踐

Fork/Jion框架第六十一頁,共86頁?;舅枷耄篊AS操作處理器指令,全稱Compareandswap,原子化的讀-該-寫指令處理競爭策略:單個線程勝出,其他線程失敗,但不會掛起第六十二頁,共86頁?;舅枷耄篈tomic原子類基于硬件CAS實現(xiàn)Atomic類分四組:計量器、域更新器、數(shù)組、復合變量更佳的volatile目標1:實現(xiàn)復雜算術運算:incrementAndGet、getAndIncrement等目標2:支持Java類型對象的CAS操作:compareAndSet第六十三頁,共86頁。基本思想:非阻塞算法一個線程的失敗或掛起不影響其他線程J.U.C的非阻塞算法依賴Atomic算法里一般采用回退機制處理Atomic的CAS競爭對死鎖免疫的同步機制目標:相對阻塞算法,減少線程切換開銷、減少鎖的競爭等。也是Lock-free,即無鎖編程第六十四頁,共86頁。無鎖棧算法:Treiber算法改進版:第六十五頁,共86頁。無鎖隊列算法:MS-Queue算法論文地址:MS-queue算法是1996年由Maged.M.MichaelandM.L.Scott提出的,是最為經(jīng)典的并發(fā)FIFO隊列上的算法,目前很多對并發(fā)FIFO隊列的研究都是基于這個算法來加以改進的。MS-queue算法的隊列用一個單鏈表來實現(xiàn),包含兩個基本的操作,enquene()和dequene(),新節(jié)點總是從隊尾最后一個元素后面加入隊列,節(jié)點元素總是從隊頭刪除。包含兩個指針,head和tail,head總是自相鏈表頭部的節(jié)點,指向的這個節(jié)點被當作是啞節(jié)點或哨兵節(jié)點,它保存的值是多少并無意義;tail總是指向鏈表中的一個節(jié)點,不一定是隊尾元素。每個節(jié)點包含兩個數(shù)據(jù)域值信息,即存放的數(shù)值信息和指向下一個節(jié)點的指針。每個指針對象,除了包含一個指向節(jié)點的指針外,還包含一個時間戳,初試時時戳為零,每修改一次指針,時戳增加一,在64位系統(tǒng)中,無需考慮時戳溢出的影響。第六十六頁,共86頁。無鎖隊列算法:Optitmistic算法Optimistic算法對于上面提到的MS-queue算法的改進就在于使用普通的store指令代替代價昂貴的CAS指令。Optimistic算法的高效性在于使用雙向鏈表表示隊列,并且入隊和出隊操作都只需要一次成功的CAS操作。該算法保證鏈表總是連接的,next指針總是一致的,當prev指針出現(xiàn)不一致時通過調用fixList方法能夠恢復到一致性狀態(tài)。同MS-queue算法一樣,optimistic算法也用到了原子化的指令Compare-and-s),CAS(a,p,n),原子化的將內存地址a中的值與p進行比較,如果二者相等,就將n寫入地址a中并返回true,否則返回false。由于optimistic算法使用了CAS指令,所以經(jīng)典的ABA問題同樣會出現(xiàn),解決方案同MS-queue相同,即使用標簽機制。論文地址:第六十七頁,共86頁。Atomic實現(xiàn)publicfinalintincrementAndGet(){for(;;){intcurrent=get();intnext=current+1;if(compareAndSet(current,next))returnnext;}}publicfinalbooleancompareAndSet(intexpect,intupdate){

returnpareAndS(this,valueOffset,expect,update);

}當importsun.misc.Unsafe;這個的時候,就因為各種問題(例如:專利)看不到源碼了。第六十八頁,共86頁。好東東:AtomicReferenceLock-free的數(shù)據(jù)結構就靠這個了,無論你喜歡與否,玩無鎖編程,你都繞不開這個類。看amino框架的源碼,你會發(fā)現(xiàn)這個妞無處不在。當然,還是AtomicInteger比較實用,多線程計數(shù)的時候,你會喜歡的。第六十九頁,共86頁。編程實踐:使用更優(yōu)的鎖第七十頁,共86頁。編程實踐:使用更優(yōu)的鎖ReentrantLock比較內部鎖在JDK的性能提升對比

第七十一頁,共86頁。編程實踐:使用更優(yōu)的鎖讀-寫鎖對比互斥鎖ReentrantLock的性能

第七十二頁,共86頁。編程實踐:縮小鎖的范圍減少線程把持鎖的時間避免在臨界區(qū)進行耗時計算常見做法1:縮小同步快常見做法2:把一個同步塊分拆成多個需要保證業(yè)務邏輯正確為前提第七十三頁,共86頁。編程實踐:避免熱點域熱點域:每次操作,都需要訪問修改的fieldseg.ConcurrentHashMap的size計算問題第七十四頁,共86頁。編程實踐:使用不變和ThreadLocal的數(shù)據(jù)不變數(shù)據(jù),即Immutable類型數(shù)據(jù)、在其生命周期中始終保持不變,可以安全地在每個線程中復制一份以便快速讀取。ThreadLocal數(shù)據(jù),只被線程本身使用,因此不存在不同線程之間的共享數(shù)據(jù)的問題。第七十五頁,共86頁。編程實踐:使用高并發(fā)容器J.U.C的高效地線程安全的并發(fā)容器Amino提供更多非阻塞的容器第七十六頁,共86頁。編程實踐:高速緩存計算結果利用空間換時間避免了重復計算相同的數(shù)據(jù)第七十七頁,共86頁。編程實踐:文檔化對外接口的同步策略如果一個類沒有明確指明,就不要假設它是線程安全的第七十八頁,共86頁。編程實踐:安全發(fā)布@NotThreadSafepublicclassUnsafeLazyInitialization{privatestaticResourceresource;publicstaticResourcegetInstance(){if(resource==null)resource=newResource();//unsafepublicationreturnresource;}}@ThreadSafepublicclassSafeLazyInitialization{privatestaticResourceresource;publicsynchronizedstaticResourcegetInstance(){if(resource==null)resource=newResource();returnresource;}}第七十九頁,共86頁。編程實

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論