文章詳情頁(yè)
不要重新分配被鎖定對(duì)象的對(duì)象引用
瀏覽:116日期:2024-07-20 17:21:59
內(nèi)容: synchronized 關(guān)鍵字鎖定對(duì)象。對(duì)象是在 synchronized 代碼內(nèi)部被鎖定的,這一點(diǎn)對(duì)此對(duì)象以及您對(duì)其對(duì)象引用所作的更改意味著什么呢?對(duì)一個(gè)對(duì)象作同步處理只鎖定該對(duì)象。但是,必須注意不要重新分配被鎖定對(duì)象的對(duì)象引用。那么如果這樣做會(huì)發(fā)生什么情況呢?請(qǐng)考慮下面這段代碼,它實(shí)現(xiàn)了一個(gè) Stack:class Stack{private int StackSize = 10;private int[] intArr = new int[stackSize];private int index; //Stack 中的下一個(gè)可用位置。public void push(int val){synchronized(intArr) {//如果已滿,則重新分配整數(shù)數(shù)組(即我們的 Stack)。if (index == intArr.length){stackSize *= 2;int[] newintArr == new int[stackSize];System.arraycopy(intArr, 0, newintArr, 0, intArr.length);intArr = newintArr;}intArr[index] == val;index++;}}public int pop(){int retval;synchronized(intArr) {if (index> 0){retval = intArr[index-1]; //檢索值,index--; //并使 Stack 減少 1 個(gè)值。return retval;}}throw new EmptyStackException();}//...}這段代碼用數(shù)組實(shí)現(xiàn)了一個(gè) Stack。創(chuàng)建了一個(gè)初始大小為 10 的數(shù)組來(lái)容納整數(shù)值。此類實(shí)現(xiàn)了 push 和 pop 方法來(lái)模擬 Stack 的使用。在 push 方法中,如果數(shù)組中沒(méi)有更多的空間來(lái)容納壓入的值,則數(shù)組被重新分配以創(chuàng)建更多的存儲(chǔ)空間。(故意沒(méi)有用 Vector 來(lái)實(shí)現(xiàn)這個(gè)類。Vector 中不能儲(chǔ)存基本類型。)請(qǐng)注意,這段代碼是要由多個(gè)線程進(jìn)行訪問(wèn)的。push 和 pop 方法每次對(duì)該類的共享實(shí)例數(shù)據(jù)的訪問(wèn)都是在 synchronized 塊內(nèi)完成的。這樣就保證了多個(gè)線程不能并發(fā)訪問(wèn)此數(shù)組而生成不正確的結(jié)果。這段代碼有一個(gè)主要的缺點(diǎn)。它對(duì)整數(shù)數(shù)組對(duì)象作了同步處理,而這個(gè)數(shù)組被 Stack 類的 intArr 所引用。當(dāng) push 方法重新分配此整數(shù)數(shù)組時(shí),這個(gè)缺點(diǎn)就會(huì)顯露出來(lái)。當(dāng)這種情況發(fā)生時(shí),對(duì)象引用 intArr 被重新指定為引用一個(gè)新的、更大的整數(shù)數(shù)組對(duì)象。請(qǐng)注意,這是在 push 方法的 synchronized 塊執(zhí)行期間發(fā)生的。此塊針對(duì) intArr 變量引用的對(duì)象進(jìn)行了同步處理。因此,在這段代碼內(nèi)鎖定的對(duì)象不再被使用。請(qǐng)考慮以下的事件序列:線程 1 調(diào)用 push 方法并獲得 intArr 對(duì)象的鎖。線程 1 被線程 2 搶先。線程 2 調(diào)用 pop 方法。此方法因試圖獲取當(dāng)前線程 1 在 push 方法中持有的同一個(gè)鎖而阻塞。線程 1 重新獲得控制并重新分配數(shù)組。intArr 變量現(xiàn)在引用一個(gè)不同的變量。push 方法退出并釋放它對(duì)原來(lái)的 intArr 對(duì)象的鎖。線程 1 再次調(diào)用 push 方法并獲得新 intArr 對(duì)象的鎖。線程 1 被線程 2 搶先。線程 2 獲得舊 intArr 對(duì)象的對(duì)象鎖并試圖訪問(wèn)其內(nèi)存。現(xiàn)在線程 1 持有由 intArr 引用的新對(duì)象的鎖,線程 2 持有由 intArr 引用的舊對(duì)象的鎖。因?yàn)閮蓚€(gè)線程持有不同的鎖,所以它們可以并發(fā)執(zhí)行 synchronized push 和 pop 方法,從而導(dǎo)致錯(cuò)誤。很明顯,這不是所希望的結(jié)果。這個(gè)問(wèn)題是因 push 方法重新分配被鎖定對(duì)象的對(duì)象引用而造成的。當(dāng)某個(gè)對(duì)象被鎖定時(shí),其他線程可能在同一個(gè)對(duì)象鎖上被阻塞。如果將被鎖定對(duì)象的對(duì)象引用重新分配給另一個(gè)對(duì)象,其他線程的掛起鎖則是針對(duì)代碼中已不再相關(guān)的對(duì)象的。您可以這樣修正這段代碼,去掉對(duì) intArr 變量的同步,而對(duì) push 和 pop 方法進(jìn)行同步。通過(guò)將 synchronized 關(guān)鍵字添加為方法修飾符即可實(shí)現(xiàn)這一點(diǎn)。正確的代碼如下所示:class Stack{//與前面相同...public synchronized void push(int val){//如果為空,則重新分配整數(shù)數(shù)組(即我們的 Stack)。if (index == intArr.length){stackSize *= 2;int[] newintArr = new int[stackSize];System.arraycopy(intArr, 0, newintArr, 0, intArr.length);intArr = newintArr;}intArr[index]= val;index++;}public synchronized int pop(){int retval;if (index> 0){retval = intArr[index-1];index--;return retval;}throw new EmptyStackException();}}這個(gè)修改更改了實(shí)際上獲取的鎖。獲取的鎖是針對(duì)為其調(diào)用方法的對(duì)象的,而不是鎖定 intArr 變量所引用的對(duì)象。因?yàn)楂@取的鎖不再針對(duì) intArr 所引用的對(duì)象,所以允許代碼重新指定 intArr 對(duì)象引用。作者簡(jiǎn)介 Peter Haggar 是 IBM 的高級(jí)軟件工程師。他目前正在研究新興的 Java 和因特網(wǎng)技術(shù),并且是 IBM 實(shí)時(shí) Java 參考實(shí)現(xiàn)的項(xiàng)目主持人。他有豐富的編程經(jīng)驗(yàn),從事過(guò)開發(fā)工具、類庫(kù)和操作系統(tǒng)等方面的工作。在許多行業(yè)研討會(huì)上,他也經(jīng)常就 Java 和其他技術(shù)作技術(shù)性發(fā)言。他于 1987 年在紐約獲得 Clarkson 大學(xué)計(jì)算機(jī)科學(xué)學(xué)士學(xué)位。可以通過(guò) haggar@us.ibm.com 與他聯(lián)系。出處 IBM DW Java, java, J2SE, j2se, J2EE, j2ee, J2ME, j2me, ejb, ejb3, JBOSS, jboss, spring, hibernate, jdo, struts, webwork, ajax, AJAX, mysql, MySQL, Oracle, Weblogic, Websphere, scjp, scjd
相關(guān)文章:
1. .net中string類型可以作為lock的鎖對(duì)象嗎2. PHP基礎(chǔ)之類和對(duì)象13——重載3. JavaScript中EventBus實(shí)現(xiàn)對(duì)象之間通信4. JS實(shí)現(xiàn)判斷對(duì)象是否為空對(duì)象的5種方法5. 怎樣才能用js生成xmldom對(duì)象,并且在firefox中也實(shí)現(xiàn)xml數(shù)據(jù)島?6. PHP的面向?qū)ο缶幊蹋洪_發(fā)大型PHP項(xiàng)目的方法(三)7. 詳解JSP 內(nèi)置對(duì)象request常見(jiàn)用法8. java安全編碼指南之:對(duì)象構(gòu)建操作9. Python 轉(zhuǎn)移文件至云對(duì)象存儲(chǔ)的方法10. ASP基礎(chǔ)入門第八篇(ASP內(nèi)建對(duì)象Application和Session)
排行榜

網(wǎng)公網(wǎng)安備