薛 嵐(江西信息應(yīng)用職業(yè)技術(shù)學(xué)院 計算機技術(shù)系,南昌 330043)
同步機制實現(xiàn)多線程有序訪問資源
薛嵐
(江西信息應(yīng)用職業(yè)技術(shù)學(xué)院計算機技術(shù)系,南昌330043)
摘要:當多個線程競爭訪問同一個資源時,Java提供了線程同步這種機制來協(xié)調(diào)各個線程的訪問。由于線程同步的復(fù)雜性,很多時候開發(fā)人員弄不清楚資源是什么、線程何時處于競爭狀態(tài),線程同步如何使用等問題,本文將對線程同步問題做深入探討。
關(guān)鍵詞:線程;同步;資源;鎖
多線程是指在同一個程序中同時存在幾個執(zhí)行體,按幾條不同的執(zhí)行路徑共同工作的情況。Java允許多線程并發(fā)控制,當多個線程訪問同一資源時,也就是多個線程同時競爭一個資源同時操作一個可共享的資源變量時(如數(shù)據(jù)的增刪改查),將會導(dǎo)致數(shù)據(jù)不準確,相互之間產(chǎn)生沖突,如果協(xié)調(diào)不好就會出現(xiàn)數(shù)據(jù)不一致的問題。因此當多個線程訪問同一資源時,因此加入同步鎖讓某一個線程獨占此資源,也就是鎖定該資源,其它線程在此時此刻不能訪問該資源,以避免在該線程沒有完成操作之前,被其他線程的調(diào)用,稱為線程同步。從而保證了該變量的唯一性和準確性。
在Java代碼中運用線程同步機制,有兩個關(guān)鍵處的代碼需要完成:1、當多個線程競爭訪問同一個對象或同一變量時,該對象或變量為競爭資源標識為private;2、當某一個方法或某一段代碼在某一個時刻只能被一個線程獨自訪問,用synchronized關(guān)鍵字標識方法或代碼為同步。synchronized只能標記非抽象的方法,不能標識成員變量。
(1)synchronized方法。用synchronized關(guān)鍵字修飾一個方法,該方法為同步方法。Java中的每個對象資源都有一個鎖,或者叫做監(jiān)視器,當一個線程訪問某個對象的同步方法時,該對象被鎖住,其他任何線程無法去訪問該對象的同步方法了,相當于對象被一個線程獨占。直到該線程線程執(zhí)行方法完畢后(或者是拋出了異常),才將該對象解鎖,釋放對象資源,其他線程才有可能再去訪問該對象的同步方法。
用同步方法實現(xiàn)類成員變量的訪問:Java系統(tǒng)為每個類實例都配了一把鎖,當要用類實例來調(diào)用同步方法時需要獲得這個類實例的鎖才能執(zhí)行,此時進入線程運行狀態(tài),否則就為線程阻塞。
同步方法一旦被執(zhí)行執(zhí)行,其它類實例將無法訪問,直到同步方法返回釋放鎖,其它類實例才有可能訪問此方法。被阻塞的其它線程才能獲得該鎖,重新進入可執(zhí)行狀態(tài)。這種機制保證了類中所有同步成員方法在同一時刻只有一個可被類實例訪問,因為只有獲得了類實例對應(yīng)的鎖的同步成員方法才能被訪問,從而有效避免了類成員方法的訪問矛盾。在Java中,除了類實例以外,每一個類也對應(yīng)一把鎖,因此也可將類的靜態(tài)成員方法聲明為同步,以避免對類的靜態(tài)成員的訪問沖突。
同步方法的缺點:有些方法若聲明為同步將會很大程度地降低執(zhí)行效率,線程類的run()方法不能聲明為同步,否則它對本類中的任何同步方法的調(diào)用都不會成功。同步機制需要占用大量內(nèi)存,而且如果使用不當易造成死鎖。
(2)synchronized塊。將需要被線程獨占訪問的代碼用大括號括起來前面標識為synchronized,則系統(tǒng)自動為該段語句塊加上內(nèi)置鎖,從而構(gòu)成同步代碼塊。
同步代碼塊中的代碼必須獲得類對象或類的鎖才能被線程訪問執(zhí)行。由于任何代碼塊都可以標識為同步,并且可獲得任意對象上的鎖,所以同步代碼塊運用方便靈活。
(3)使用特殊域變量實現(xiàn)線程同步。1).volatile關(guān)鍵字為域變量的訪問提供了一種免鎖機制;2).使用volatile修飾域相當于告訴虛擬機該域可能會被其他線程更新;3).因此每次使用該域就要重新計算,而不是使用寄存器中的值;4).volatile不會提供任何原子操作,它也不能用來修飾final類型的變量
(4)使用重入鎖實現(xiàn)線程同步。可重入的互斥鎖具有與使用同步方法和語句所訪問的隱式監(jiān)視器鎖相同的一些基本行為和語義,但功能更強大。它由最近成功獲得鎖,并且還沒有釋放該鎖的線程擁有。
(5)使用局部變量實現(xiàn)線程同步
(1)無論方法還是代碼標識為同步,鎖住的資源是指對象,而且只要不是多個線程同時訪問同步方法和代碼塊,其還可以被其他線程的對象訪問,。
(2)每個對象只對應(yīng)一個鎖,即一個對象只與一個鎖相關(guān)聯(lián)。
(3)使用同步機制時需要謹慎,能不用同步實現(xiàn)的操作就不用同步實現(xiàn)。因為使用同步需要占用很大的系統(tǒng)內(nèi)存,開銷很大就有可能造成死鎖。
(4)當兩個線程同時搶占同一個對象中的同步方法或變量時,只能有一個線程可以執(zhí)行訪問同步方法或變量。另一個線程進入暫時等待狀態(tài)必須等待當前線程執(zhí)行完才能訪問。
(5)當一個線程訪問對象中的一個同步代碼塊時,這個對象中的其它同步代碼塊也會被鎖住,也就是對其它線程關(guān)閉。
(6)當一個線程訪問對象的一個同步代碼塊時,該對象中的非同步方法或變量不受影響,可以被其它線程訪問。
(7)當一個線程訪問一個對象的某個同步代碼塊時,該對象的對象鎖就自動賦給了此線程。即此線程獨占該對象的所有同步方法和變量,禁止同一時刻其它線程對該對象上任何同步方法和變量的訪問。
(1)線程同步機制是為了防止多個線程競爭同一資源時由于沒協(xié)調(diào)好而出現(xiàn)線程對資源數(shù)據(jù)修改的不一致。
(2)線程同步機制需要通過鎖來實現(xiàn),每個對象都有一把鎖。當一個線程獲得了一個對象上的鎖,其它線程在同一時刻就不能訪問該對象上的所有同步方法和同步變量
(3)對于靜態(tài)同步方法,鎖是針對這個類的,鎖對象是該類的Class對象。靜態(tài)和非靜態(tài)方法的鎖互不干預(yù)。一個線程獲得鎖,在一個同步方法中訪問另一個對象上的同步方法時,會獲取這兩個對象鎖。
(4)使用同步時,要注意在是哪個對象上同步,否則會出現(xiàn)對象不一致。
(5)當多個線程競爭一個資源時,只有獲得對象鎖的線程才能訪問資源,沒有獲取對象鎖的線程將處于暫時阻塞狀態(tài)。
(6)死鎖是多個線程需要獲得其它線程占有的資源后才能完成操作,而每個線程又都不肯釋放自己占有的資源,造成永遠相互等待。
參考文獻:
[1]張榮海.Java多線程同步方法的研究[J].黑龍江科技信息,2003 (05).
作者簡介:薛嵐(1980-),女,江西南昌人,碩士,講師,研究方向:軟件技術(shù)專業(yè)Java方向。