成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

Slipped Conditions簡析

mcterry / 1611人閱讀

摘要:為避免,條件的檢查與設(shè)置必須是原子的,也就是說,在第一個線程檢查和設(shè)置條件期間,不會有其它線程檢查這個條件。為避免這個問題,我們必須將塊移出塊。細(xì)心的讀者可能會注意到上面的公平鎖實(shí)現(xiàn)仍然有可能丟失信號。這些方法會在內(nèi)部對信號進(jìn)行存儲和響應(yīng)。

所謂Slipped conditions,就是說, 從一個線程檢查某一特定條件到該線程操作此條件期間,這個條件已經(jīng)被其它線程改變,導(dǎo)致第一個線程在該條件上執(zhí)行了錯誤的操作。這里有一個簡單的例子:

public class Lock {
    private boolean isLocked = true;

    public void lock(){
      synchronized(this){
        while(isLocked){
          try{
            this.wait();
          } catch(InterruptedException e){
            //do nothing, keep waiting
          }
        }
      }

      synchronized(this){
        isLocked = true;
      }
    }

    public synchronized void unlock(){
      isLocked = false;
      this.notify();
    }
}

我們可以看到,lock()方法包含了兩個同步塊。第一個同步塊執(zhí)行wait操作直到isLocked變?yōu)閒alse才退出,第二個同步塊將isLocked置為true,以此來鎖住這個Lock實(shí)例避免其它線程通過lock()方法。

我們可以設(shè)想一下,假如在某個時刻isLocked為false, 這個時候,有兩個線程同時訪問lock方法。如果第一個線程先進(jìn)入第一個同步塊,這個時候它會發(fā)現(xiàn)isLocked為false,若此時允許第二個線程執(zhí)行,它也進(jìn)入第一個同步塊,同樣發(fā)現(xiàn)isLocked是false?,F(xiàn)在兩個線程都檢查了這個條件為false,然后它們都會繼續(xù)進(jìn)入第二個同步塊中并設(shè)置isLocked為true。

這個場景就是slipped conditions的例子,兩個線程檢查同一個條件, 然后退出同步塊,因此在這兩個線程改變條件之前,就允許其它線程來檢查這個條件。換句話說,條件被某個線程檢查到該條件被此線程改變期間,這個條件已經(jīng)被其它線程改變過了。

為避免slipped conditions,條件的檢查與設(shè)置必須是原子的,也就是說,在第一個線程檢查和設(shè)置條件期間,不會有其它線程檢查這個條件。

解決上面問題的方法很簡單,只是簡單的把isLocked = true這行代碼移到第一個同步塊中,放在while循環(huán)后面即可:

public class Lock {
    private boolean isLocked = true;

    public void lock(){
      synchronized(this){
        while(isLocked){
          try{
            this.wait();
          } catch(InterruptedException e){
            //do nothing, keep waiting
          }
        }
        isLocked = true;
      }
    }

    public synchronized void unlock(){
      isLocked = false;
      this.notify();
    }
}

現(xiàn)在檢查和設(shè)置isLocked條件是在同一個同步塊中原子地執(zhí)行了。

一個更現(xiàn)實(shí)的例子

也許你會說,我才不可能寫這么挫的代碼,還覺得slipped conditions是個相當(dāng)理論的問題。但是第一個簡單的例子只是用來更好的展示slipped
conditions。

饑餓和公平中實(shí)現(xiàn)的公平鎖也許是個更現(xiàn)實(shí)的例子。再看下嵌套管程鎖死中那個幼稚的實(shí)現(xiàn),如果我們試圖解決其中的嵌套管程鎖死問題,很容易產(chǎn)生slipped conditions問題。

首先讓我們看下嵌套管程鎖死中的例子:

//Fair Lock implementation with nested monitor lockout problem
public class FairLock {
  private boolean isLocked = false;
  private Thread lockingThread = null;
  private List waitingThreads =
            new ArrayList();

  public void lock() throws InterruptedException{
    QueueObject queueObject = new QueueObject();

    synchronized(this){
      waitingThreads.add(queueObject);

      while(isLocked || waitingThreads.get(0) != queueObject){

        synchronized(queueObject){
          try{
            queueObject.wait();
          }catch(InterruptedException e){
            waitingThreads.remove(queueObject);
            throw e;
          }
        }
      }
      waitingThreads.remove(queueObject);
      isLocked = true;
      lockingThread = Thread.currentThread();
    }
  }

  public synchronized void unlock(){
    if(this.lockingThread != Thread.currentThread()){
      throw new IllegalMonitorStateException(
        "Calling thread has not locked this lock");
    }
    isLocked      = false;
    lockingThread = null;
    if(waitingThreads.size() > 0){
      QueueObject queueObject = waitingThread.get(0);
      synchronized(queueObject){
        queueObject.notify();
      }
    }
  }
}
public class QueueObject {}

我們可以看到synchronized(queueObject)及其中的queueObject.wait()調(diào)用是嵌在synchronized(this)塊里面的,這會導(dǎo)致嵌套管程鎖死問題。為避免這個問題,我們必須將synchronized(queueObject)塊移出synchronized(this)塊。移出來之后的代碼可能是這樣的:

//Fair Lock implementation with slipped conditions problem
public class FairLock {
  private boolean isLocked = false;
  private Thread lockingThread  = null;
  private List waitingThreads =
            new ArrayList();

  public void lock() throws InterruptedException{
    QueueObject queueObject = new QueueObject();

    synchronized(this){
      waitingThreads.add(queueObject);
    }

    boolean mustWait = true;
    while(mustWait){

      synchronized(this){
        mustWait = isLocked || waitingThreads.get(0) != queueObject;
      }

      synchronized(queueObject){
        if(mustWait){
          try{
            queueObject.wait();
          }catch(InterruptedException e){
            waitingThreads.remove(queueObject);
            throw e;
          }
        }
      }
    }

    synchronized(this){
      waitingThreads.remove(queueObject);
      isLocked = true;
      lockingThread = Thread.currentThread();
    }
  }
}

注意:因?yàn)槲抑桓膭恿薼ock()方法,這里只展現(xiàn)了lock方法。

現(xiàn)在lock()方法包含了3個同步塊。

第一個,synchronized(this)塊通過mustWait = isLocked || waitingThreads.get(0) != queueObject檢查內(nèi)部變量的值。

第二個,synchronized(queueObject)塊檢查線程是否需要等待。也有可能其它線程在這個時候已經(jīng)解鎖了,但我們暫時不考慮這個問題。我們就假設(shè)這個鎖處在解鎖狀態(tài),所以線程會立馬退出synchronized(queueObject)塊。

第三個,synchronized(this)塊只會在mustWait為false的時候執(zhí)行。它將isLocked重新設(shè)回true,然后離開lock()方法。

設(shè)想一下,在鎖處于解鎖狀態(tài)時,如果有兩個線程同時調(diào)用lock()方法會發(fā)生什么。首先,線程1會檢查到isLocked為false,然后線程2同樣檢查到isLocked為false。接著,它們都不會等待,都會去設(shè)置isLocked為true。這就是slipped
conditions的一個最好的例子。

解決Slipped Conditions問題

要解決上面例子中的slipped conditions問題,最后一個synchronized(this)塊中的代碼必須向上移到第一個同步塊中。為適應(yīng)這種變動,代碼需要做點(diǎn)小改動。下面是改動過的代碼:

//Fair Lock implementation without nested monitor lockout problem,
//but with missed signals problem.
public class FairLock {
  private boolean isLocked = false;
  private Thread lockingThread  = null;
  private List waitingThreads =
            new ArrayList();

  public void lock() throws InterruptedException{
    QueueObject queueObject = new QueueObject();

    synchronized(this){
      waitingThreads.add(queueObject);
    }

    boolean mustWait = true;
    while(mustWait){
      synchronized(this){
        mustWait = isLocked || waitingThreads.get(0) != queueObject;
        if(!mustWait){
          waitingThreads.remove(queueObject);
          isLocked = true;
          lockingThread = Thread.currentThread();
          return;
        }
      }     

      synchronized(queueObject){
        if(mustWait){
          try{
            queueObject.wait();
          }catch(InterruptedException e){
            waitingThreads.remove(queueObject);
            throw e;
          }
        }
      }
    }
  }
}

我們可以看到對局部變量mustWait的檢查與賦值是在同一個同步塊中完成的。還可以看到,即使在synchronized(this)塊外面檢查了mustWait,在while(mustWait)子句中,mustWait變量從來沒有在synchronized(this)同步塊外被賦值。當(dāng)一個線程檢查到mustWait是false的時候,它將自動設(shè)置內(nèi)部的條件(isLocked),所以其它線程再來檢查這個條件的時候,它們就會發(fā)現(xiàn)這個條件的值現(xiàn)在為true了。

synchronized(this)塊中的return;語句不是必須的。這只是個小小的優(yōu)化。如果一個線程肯定不會等待(即mustWait為false),那么就沒必要讓它進(jìn)入到synchronized(queueObject)同步塊中和執(zhí)行if(mustWait)子句了。

細(xì)心的讀者可能會注意到上面的公平鎖實(shí)現(xiàn)仍然有可能丟失信號。設(shè)想一下,當(dāng)該FairLock實(shí)例處于鎖定狀態(tài)時,有個線程來調(diào)用lock()方法。執(zhí)行完第一個 synchronized(this)塊后,mustWait變量的值為true。再設(shè)想一下調(diào)用lock()的線程是通過搶占式的,擁有鎖的那個線程那個線程此時調(diào)用了unlock()方法,但是看下之前的unlock()的實(shí)現(xiàn)你會發(fā)現(xiàn),它調(diào)用了queueObject.notify()。但是,因?yàn)閘ock()中的線程還沒有來得及調(diào)用queueObject.wait(),所以queueObject.notify()調(diào)用也就沒有作用了,信號就丟失掉了。如果調(diào)用lock()的線程在另一個線程調(diào)用queueObject.notify()之后調(diào)用queueObject.wait(),這個線程會一直阻塞到其它線程調(diào)用unlock方法為止,但這永遠(yuǎn)也不會發(fā)生。

公平鎖實(shí)現(xiàn)的信號丟失問題在饑餓和公平一文中我們已有過討論,把QueueObject轉(zhuǎn)變成一個信號量,并提供兩個方法:doWait()和doNotify()。這些方法會在QueueObject內(nèi)部對信號進(jìn)行存儲和響應(yīng)。用這種方式,即使doNotify()在doWait()之前調(diào)用,信號也不會丟失。

原文 Slipped Conditions
作者 Jakob Jenkov
譯者 余紹亮
via ifeve

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/69767.html

相關(guān)文章

  • Java多線程學(xué)習(xí)——公平鎖

    饑餓和公平:http://ifeve.com/starvation-a...嵌套管程鎖死:http://ifeve.com/nested-monit...Slipped Conditions:http://ifeve.com/slipped-cond... 待總結(jié),建議三部分結(jié)合看

    Jioby 評論0 收藏0
  • Java并發(fā)

    摘要:饑餓和公平一個線程因?yàn)闀r間全部被其他線程搶走而得不到運(yùn)行時間,這種狀態(tài)被稱之為饑餓。線程需要同時持有對象和對象的鎖,才能向線程發(fā)信號。現(xiàn)在兩個線程都檢查了這個條件為,然后它們都會繼續(xù)進(jìn)入第二個同步塊中并設(shè)置為。 1、死鎖 產(chǎn)生死鎖的四個必要條件:(1) 互斥條件:一個資源每次只能被一個進(jìn)程使用。(2) 請求與保持條件:一個進(jìn)程因請求資源而阻塞時,對已獲得的資源保持不放。(3) 不剝奪條...

    venmos 評論0 收藏0
  • PHP中一個 & 和兩個 && 的區(qū)別簡析

    摘要:幾個例子輸出簡析表達(dá)式從左到右依次執(zhí)行。數(shù)字轉(zhuǎn)換成二進(jìn)制所以 兩個 && 是邏輯 與。一個 & 是按位與。 幾個例子: if (($a = 1) & ($a == 1) & ($a = 3)) { echo true, $a;die; } echo false, $a; 輸出:true3 簡析:表達(dá)式從左到右依次執(zhí)行。 if (false & ($a = 3)) { ...

    hot_pot_Leo 評論0 收藏0
  • Webpack模塊化原理簡析

    摘要:模塊化原理簡析的核心原理一切皆模塊在中,,靜態(tài)資源文件等都可以視作模塊便于管理,利于重復(fù)利用按需加載進(jìn)行代碼分割,實(shí)現(xiàn)按需加載。模塊化原理以為例,分析構(gòu)建的模塊化方式。 webpack模塊化原理簡析 1.webpack的核心原理 一切皆模塊:在webpack中,css,html.js,靜態(tài)資源文件等都可以視作模塊;便于管理,利于重復(fù)利用; 按需加載:進(jìn)行代碼分割,實(shí)現(xiàn)按需加載。 2...

    tracy 評論0 收藏0
  • 混合式多云架構(gòu)簡析

    摘要:在行業(yè),制作和管理混合多云架構(gòu)所需的工具和技術(shù)是分散的。針對上述挑戰(zhàn),本文特意介紹了兩種混合式多云架構(gòu),將內(nèi)部環(huán)境遷移到混合式多云環(huán)境。一多應(yīng)用重新綁定在上述混合式多云架構(gòu)中,重新架構(gòu)的應(yīng)用部署在多個云環(huán)境中。當(dāng)企業(yè)決定在多個本地、托管、私有以及公有云服務(wù)中轉(zhuǎn)移工作負(fù)載、數(shù)據(jù)及流程時,就需要一種新的方法,從而促使了混合式多云管理的誕生。但是這種方法在計費(fèi)和供應(yīng)、訪問控制、成本控制、性能分析及...

    piapia 評論0 收藏0

發(fā)表評論

0條評論

閱讀需要支付1元查看
<