Java并发,并行,同步,互斥
2019獨角獸企業(yè)重金招聘Python工程師標準>>>
???? ??一切都要從這個世界的并行性開始說,事物的發(fā)展總是并行進行的,汽車在奔馳的同時,自行車也在行駛;別人正在唱歌,你可能正在吃飯;等等。這些都是并行的例子,就單個事物來看,它發(fā)展的動作一般是順序進行,而多個事物之間一般誰也不會妨礙誰,除非它們的動作要作用在同一個對象上:汽車過十字路口的綠燈時,另一個方向的汽車就不能行駛;如果你在食堂里舉辦歌舞晚會,別人就不能在這兒吃飯。
計算機軟件的基本模型是順序執(zhí)行的,然而現(xiàn)代計算機在此基礎上發(fā)展出了并發(fā)概念。什么是并發(fā)?什么是并行?它們之間的區(qū)別是什么?并發(fā)與并行是兩個既相似而又不相同的概念:并發(fā)性,又稱共行性,是指能處理多個同時性活動的能力;并行是指同時發(fā)生的兩個并發(fā)事件,具有并發(fā)的含義,而并發(fā)則不一定并行,也亦是說并發(fā)事件之間不一定要同一時刻發(fā)生。并行一般是指沒有互斥和同步的情況下獨立進行并同時發(fā)生的事件。因此單CPU操作系統(tǒng)的進程/線程嚴格意義上來說都不能算是并行事件,畢竟它們都要使用同一個CPU,真正的并行出現(xiàn)在多處理器的計算機上,當進程/線程獨立運行在不同的CPU上,而且不需要共享對象時。粗略的說,沒有資源互斥共享的進程和線程都是并行的。
如果進程/線程沒有共享任何數(shù)據(jù),它們編程所關心的許多概念就不會存在。就像現(xiàn)實世界,如果任何兩個人都是獨立的,沒有任何關系的,那么也不會存在社會的各種機構來協(xié)調這些關系。在操作系統(tǒng)中,進程之間共享數(shù)據(jù)的方式一般通過IO(如:文件、管道、網(wǎng)絡端口等等),當然也有時會通過內存共享。這種松耦合的共享造成的同步、互斥問題并不多。常見的同步問題發(fā)生同一進程內不同線程之間。由于線程存在于同個進程中,它們之間是可以共享內存的,所以就會有很多同步和互斥的問題。
那么什么是同步,什么是互斥?同步和互斥往往是共生的。所謂的同步是指不同實體的動作按照某些特定條件的順序執(zhí)行。最常見的莫過于生產(chǎn)者和消費者之間的關系。生產(chǎn)者的生產(chǎn)動作和消費者的消費動作是必須滿足先后順序的:只有生產(chǎn)者生產(chǎn)出東西來,消費者才能消費這些東西。它們之間就需要所謂的同步。什么是互斥?互斥是指兩個實體的動作不允許同時發(fā)生,如果同時發(fā)生就會產(chǎn)生不可以預期的結果。互斥是同步的前提,如果兩個動作不是互斥的,就不可能保證其發(fā)生的順序。同步一定是互斥的,而互斥不一定需要同步。同步是固定順序的動作的互斥。理解這一點非常重要。
舉個我們都熟悉的例子,多個并發(fā)生產(chǎn)者和多個并發(fā)消費者。生產(chǎn)者生產(chǎn)的對象放在一個數(shù)組中,而消費者則從這個數(shù)組中獲取對象。那么生產(chǎn)者的生產(chǎn)動作之間是需要互斥的,但不需要同步。不管是A先放在數(shù)組,還是B先放在數(shù)組中,它們之間除了為避免將產(chǎn)品放在數(shù)組中同一位置上,需要互斥地訪問數(shù)組外,是不需要規(guī)定哪一個在前面放,哪一個在后面放的。它們之間的關系就屬于互斥。而生產(chǎn)者和消費者之間就存在一個先后順序問題,必須至少有生產(chǎn)者生產(chǎn)出產(chǎn)品放在數(shù)組中,消費者才能開始消費。因此生產(chǎn)者生產(chǎn)和消費者消費之間的就是同步關系。此外,消費者和消費者之間的消費關系也是需要互斥的,這樣才能避免兩個消費者之間爭奪同數(shù)組里同一位置的對象。但是它們的消費行為是不需要同步的,只要互斥的進行就行了。
因此不同實體之間的動作有兩個基本關系:同步和互斥。一般處理同步的方法是建立在互斥的基礎上的。互斥的機制一般需要通過操作系統(tǒng)甚至底層硬件提供的信號量、管程(管程是建立在信號量基礎上的更高層構件)等底層機制來實現(xiàn)。Java語言中通過提供互斥原語synchronized(雖然叫同步,更準確的說應該是互斥mutex)來保證的,當然Java實際上是通過JVM的monitor_enter和monitor_exit指令來實現(xiàn)的,這些指令最終以底層操作系統(tǒng)提供的機制來實現(xiàn)。同步的實現(xiàn)除了要依靠互斥原語,還要結合條件判斷和線程掛起等語言構件來實現(xiàn)。其原理比較簡單,首先要通過原語synchronized互斥兩個需要同步的動作(也稱作臨界代碼),當某個動作(比如消費)獲得信號鎖進入管程時,它首先判斷某個條件是否滿足(是否有可消費對象),不滿足則掛起當前線程,釋放信號鎖,允許其他線程進入。當其他線程(比如生產(chǎn)者)進入后,也是檢查是否滿足某些條件(比如數(shù)組是否有空閑),如果不滿足則和前面線程一樣釋放信號鎖并掛起線程,如果滿足(有空閑)則進行動作(生產(chǎn)并放在數(shù)組空閑處),然后這個動作一般要負責激活其他掛起的線程(當然也可以不負責任,其結果是往往造成死鎖),然后自己釋放信號鎖退出管程。其他被激活的線程進入下一輪競爭,誰獲得信號鎖后繼續(xù)檢查它需要的條件是否滿足,如此繼續(xù)下去。
轉載于:https://my.oschina.net/plusKing/blog/668001
總結
以上是生活随笔為你收集整理的Java并发,并行,同步,互斥的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 菜鸟学自动化测试(四)----selen
- 下一篇: mysql中的时间函数---运维常用