最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解Java Slipped Conditions

 更新時間:2021年01月22日 09:27:05   作者:無才的小易  
這篇文章主要介紹了Java Slipped Conditions的相關(guān)資料,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下

所謂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實例避免其它線程通過lock()方法。

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

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

饑餓和公平中實現(xiàn)的公平鎖也許是個更現(xiàn)實的例子。再看下嵌套管程鎖死中那個幼稚的實現(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();
   }
  }
 }
}1public 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();
  }
 }
}

注意:因為我只改動了lock()方法,這里只展現(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)這種變動,代碼需要做點小改動。下面是改動過的代碼:

//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),那么就沒必要讓它進入到synchronized(queueObject)同步塊中和執(zhí)行if(mustWait)子句了。

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

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

以上就是詳解Java Slipped Conditions的詳細內(nèi)容,更多關(guān)于Java Slipped Conditions的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java畢業(yè)設(shè)計實戰(zhàn)項目之在線服裝銷售商城系統(tǒng)的實現(xiàn)流程

    Java畢業(yè)設(shè)計實戰(zhàn)項目之在線服裝銷售商城系統(tǒng)的實現(xiàn)流程

    基礎(chǔ)掌握怎么樣,用實戰(zhàn)檢驗就知道了,本篇文章手把手帶你用java+SpringBoot+Maven+Vue+mysql實現(xiàn)一個在線服裝銷售商城系統(tǒng),大家可以在過程中查缺補漏,提升水平
    2022-01-01
  • Java的Spring框架下的AOP編程模式示例

    Java的Spring框架下的AOP編程模式示例

    這篇文章主要介紹了Java的Spring框架下的AOP編程模式示例,文中分別講到了基于XML和基于@AspectJ的自定義方式,需要的朋友可以參考下
    2015-12-12
  • Java for循環(huán)幾種寫法整理

    Java for循環(huán)幾種寫法整理

    這篇文章主要介紹了Java for循環(huán)幾種寫法整理的相關(guān)資料,需要的朋友可以參考下
    2017-02-02
  • 詳解mybatis三種分頁方式

    詳解mybatis三種分頁方式

    本文主要介紹了詳解mybatis三種分頁方式,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • 使用Java和Selenium實現(xiàn)滑塊驗證的自動化登錄功能

    使用Java和Selenium實現(xiàn)滑塊驗證的自動化登錄功能

    在現(xiàn)代Web應(yīng)用中,滑塊驗證碼被廣泛用于防止自動化腳本的濫用,滑塊驗證通常要求用戶通過拖動滑塊來完成驗證,然而,在某些場景下,如自動化測試或批量登錄,我們需要通過編程手段解決滑塊驗證問題,本文將詳細介紹如何使用Java和Selenium實現(xiàn)滑塊驗證的自動化登錄
    2025-01-01
  • Spring Boot 集成MyBatis 教程詳解

    Spring Boot 集成MyBatis 教程詳解

    這篇文章主要介紹了Spring Boot 集成MyBatis 教程詳解,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2017-04-04
  • 深入淺出的學(xué)習(xí)Java ThreadLocal

    深入淺出的學(xué)習(xí)Java ThreadLocal

    本文會基于實際場景介紹ThreadLocal如何使用以及內(nèi)部實現(xiàn)機制。 具有很好的參考價值,下面跟著小編一起來看下吧
    2017-02-02
  • ssm項目實現(xiàn)用戶登陸持久化(token)

    ssm項目實現(xiàn)用戶登陸持久化(token)

    這篇文章主要介紹了ssm項目實現(xiàn)用戶登陸持久化(token),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • SpringCloud?Bus組件的使用配置詳解

    SpringCloud?Bus組件的使用配置詳解

    bus稱之為springcloud中消息總線,主要用來在微服務(wù)系統(tǒng)中實現(xiàn)遠端配置更新時通過廣播形式通知所有客戶端刷新配置信息,避免手動重啟服務(wù)的工作,這篇文章主要介紹了SpringCloud?Bus組件的使用,需要的朋友可以參考下
    2022-03-03
  • POS機如何與Java交互的方式探討

    POS機如何與Java交互的方式探討

    本文深入探討POS機與Java語言的交互機制,詳細介紹了通過RESTfulAPI、Socket編程和消息隊列等方式實現(xiàn)數(shù)據(jù)交換和功能調(diào)用,文章還包含了代碼示例、狀態(tài)圖與關(guān)系圖,幫助開發(fā)者理解和實現(xiàn)POS機與Java之間的高效交互
    2024-09-09

最新評論

若尔盖县| 仙居县| 吉林市| 穆棱市| 景德镇市| 平山县| 建平县| 关岭| 靖远县| 屏边| 芮城县| 安丘市| 天津市| 体育| 博白县| 安吉县| 峨山| 梨树县| 洛浦县| 潢川县| 福贡县| 桂阳县| 江门市| 泾源县| 宜良县| 奉节县| 清涧县| 乐清市| 岢岚县| 庆元县| 迁西县| 綦江县| 庆阳市| 肇庆市| 互助| 图们市| 西城区| 崇州市| 福州市| 邮箱| 巴林左旗|