• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
  • 不要重新分配被鎖定對象的對象引用

    發表于:2007-07-04來源:作者:點擊數: 標簽:
    synchronized 關鍵字鎖定對象。對象是在 synchronized 代碼內部被鎖定的,這一點對此對象以及您對其對象引用所作的更改意味著什么呢?對一個對象作同步處理只鎖定該對象。但是,必須注意不要重新分配被鎖定對象的對象引用。那么如果這樣做會發生什么情況呢?
    synchronized 關鍵字鎖定對象。對象是在 synchronized 代碼內部被鎖定的,這一點對此對象以及您對其對象引用所作的更改意味著什么呢?對一個對象作同步處理只鎖定該對象。但是,必須注意不要重新分配被鎖定對象的對象引用。那么如果這樣做會發生什么情況呢?請考慮下面這段代碼,它實現了一個 Stack:

    class Stack
    {
    private int StackSize = 10;
    private int[] intArr = new int[stackSize];
    private int index; //Stack 中的下一個可用位置。

    public void push(int val)
    {
    synchronized(intArr) {
    //如果已滿,則重新分配整數數組(即我們的 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 個值。
    return retval;
    }
    }
    throw new EmptyStackException();
    }
    //...
    }


    這段代碼用數組實現了一個 Stack。創建了一個初始大小為 10 的數組來容納整數值。此類實現了 push 和 pop 方法來模擬 Stack 的使用。在 push 方法中,如果數組中沒有更多的空間來容納壓入的值,則數組被重新分配以創建更多的存儲空間。(故意沒有用 Vector 來實現這個類。Vector 中不能儲存基本類型。)

    請注意,這段代碼是要由多個clearcase/" target="_blank" >cc>線程進行訪問的。push 和 pop 方法每次對該類的共享實例數據的訪問都是在 synchronized 塊內完成的。這樣就保證了多個線程不能并發訪問此數組而生成不正確的結果。

    這段代碼有一個主要的缺點。它對整數數組對象作了同步處理,而這個數組被 Stack 類的 intArr 所引用。當 push 方法重新分配此整數數組時,這個缺點就會顯露出來。當這種情況發生時,對象引用 intArr 被重新指定為引用一個新的、更大的整數數組對象。請注意,這是在 push 方法的 synchronized 塊執行期間發生的。此塊針對 intArr 變量引用的對象進行了同步處理。因此,在這段代碼內鎖定的對象不再被使用。請考慮以下的事件序列:

    線程 1 調用 push 方法并獲得 intArr 對象的鎖。


    線程 1 被線程 2 搶先。


    線程 2 調用 pop 方法。此方法因試圖獲取當前線程 1 在 push 方法中持有的同一個鎖而阻塞。


    線程 1 重新獲得控制并重新分配數組。intArr 變量現在引用一個不同的變量。


    push 方法退出并釋放它對原來的 intArr 對象的鎖。


    線程 1 再次調用 push 方法并獲得新 intArr 對象的鎖。


    線程 1 被線程 2 搶先。


    線程 2 獲得舊 intArr 對象的對象鎖并試圖訪問其內存。


    現在線程 1 持有由 intArr 引用的新對象的鎖,線程 2 持有由 intArr 引用的舊對象的鎖。因為兩個線程持有不同的鎖,所以它們可以并發執行 synchronized push 和 pop 方法,從而導致錯誤。很明顯,這不是所希望的結果。

    這個問題是因 push 方法重新分配被鎖定對象的對象引用而造成的。當某個對象被鎖定時,其他線程可能在同一個對象鎖上被阻塞。如果將被鎖定對象的對象引用重新分配給另一個對象,其他線程的掛起鎖則是針對代碼中已不再相關的對象的。

    您可以這樣修正這段代碼,去掉對 intArr 變量的同步,而對 push 和 pop 方法進行同步。通過將 synchronized 關鍵字添加為方法修飾符即可實現這一點。正確的代碼如下所示:

    class Stack
    {
    //與前面相同...
    public synchronized void push(int val)
    {
    //如果為空,則重新分配整數數組(即我們的 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();
    }
    }


    這個修改更改了實際上獲取的鎖。獲取的鎖是針對為其調用方法的對象的,而不是鎖定 intArr 變量所引用的對象。因為獲取的鎖不再針對 intArr 所引用的對象,所以允許代碼重新指定 intArr 對象引用。

    原文轉自:http://www.kjueaiud.com

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>