电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

詳解Java Slipped Conditions

瀏覽:5日期:2022-08-17 18:01:51

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

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()方法包含了兩個同步塊。第一個同步塊執行wait操作直到isLocked變為false才退出,第二個同步塊將isLocked置為true,以此來鎖住這個Lock實例避免其它線程通過lock()方法。

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

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

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

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

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(); }}

現在檢查和設置isLocked條件是在同一個同步塊中原子地執行了。

一個更現實的例子

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

饑餓和公平中實現的公平鎖也許是個更現實的例子。再看下嵌套管程鎖死中那個幼稚的實現,如果我們試圖解決其中的嵌套管程鎖死問題,很容易產生slipped conditions問題。首先讓我們看下嵌套管程鎖死中的例子:

//Fair Lock implementation with nested monitor lockout problempublic 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()調用是嵌在synchronized(this)塊里面的,這會導致嵌套管程鎖死問題。為避免這個問題,我們必須將synchronized(queueObject)塊移出synchronized(this)塊。移出來之后的代碼可能是這樣的:

//Fair Lock implementation with slipped conditions problempublic 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()方法,這里只展現了lock方法。

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

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

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

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

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

解決Slipped Conditions問題

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

//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)同步塊外被賦值。當一個線程檢查到mustWait是false的時候,它將自動設置內部的條件(isLocked),所以其它線程再來檢查這個條件的時候,它們就會發現這個條件的值現在為true了。

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

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

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

以上就是詳解Java Slipped Conditions的詳細內容,更多關于Java Slipped Conditions的資料請關注好吧啦網其它相關文章!

標簽: Java
相關文章:
主站蜘蛛池模板: 吹塑加工_大型吹塑加工_滚塑代加工-莱力奇吹塑加工有限公司 | 德州万泰装饰 - 万泰装饰装修设计软装家居馆 | 隔离变压器-伺服变压器--输入输出电抗器-深圳市德而沃电气有限公司 | 郑州爱婴幼师学校_专业幼师培训_托育师培训_幼儿教育培训学校 | 数控车床-立式加工中心-多功能机床-小型车床-山东临沂金星机床有限公司 | 全自动过滤器_反冲洗过滤器_自清洗过滤器_量子除垢环_量子环除垢_量子除垢 - 安士睿(北京)过滤设备有限公司 | 注塑机-压铸机-塑料注塑机-卧式注塑机-高速注塑机-单缸注塑机厂家-广东联升精密智能装备科技有限公司 | 全自动贴标机-套标机-工业热风机-不干胶贴标机-上海厚冉机械 | 无轨电动平车_轨道平车_蓄电池电动平车★尽在新乡百特智能转运设备有限公司 | 重庆钣金加工厂家首页-专业定做监控电视墙_操作台 | 舞台木地板厂家_体育运动木地板_室内篮球馆木地板_实木运动地板厂家_欧氏篮球地板推荐 | 蒜肠网-动漫,二次元,COSPLAY,漫展以及收藏型模型,手办,玩具的新媒体.(原变形金刚变迷TF圈) | 一航网络-软件测评官网 | 电解抛光加工_不锈钢电解抛光_常州安谱金属制品有限公司 | 北京翻译公司-专业合同翻译-医学标书翻译收费标准-慕迪灵 | 恒温恒湿试验箱厂家-高低温试验箱维修价格_东莞环仪仪器_东莞环仪仪器 | 山东太阳能路灯厂家-庭院灯生产厂家-济南晟启灯饰有限公司 | 煤棒机_增碳剂颗粒机_活性炭颗粒机_木炭粉成型机-巩义市老城振华机械厂 | 专注氟塑料泵_衬氟泵_磁力泵_卧龙泵阀_化工泵专业品牌 - 梭川泵阀 | 冷柜风机-冰柜电机-罩极电机-外转子风机-EC直流电机厂家-杭州金久电器有限公司 | 周易算网-八字测算网 - 周易算网-宝宝起名取名测名字周易八字测算网 | 成都LED显示屏丨室内户外全彩led屏厂家方案报价_四川诺显科技 | 脑钠肽-白介素4|白介素8试剂盒-研域(上海)化学试剂有限公司 | 优考试_免费在线考试系统_培训考试系统_题库系统_组卷答题系统_匡优考试 | 双能x射线骨密度检测仪_dxa骨密度仪_双能x线骨密度仪_品牌厂家【品源医疗】 | 建大仁科-温湿度变送器|温湿度传感器|温湿度记录仪_厂家_价格-山东仁科 | 专注氟塑料泵_衬氟泵_磁力泵_卧龙泵阀_化工泵专业品牌 - 梭川泵阀 | 披萨石_披萨盘_电器家电隔热绵加工定制_佛山市南海区西樵南方综合保温材料厂 | 破碎机_上海破碎机_破碎机设备_破碎机厂家-上海山卓重工机械有限公司 | 玻璃钢格栅盖板|玻璃钢盖板|玻璃钢格栅板|树篦子-长沙川皖玻璃钢制品有限公司 | Maneurop/美优乐压缩机,活塞压缩机,型号规格,技术参数,尺寸图片,价格经销商 | pbt头梳丝_牙刷丝_尼龙毛刷丝_PP塑料纤维合成毛丝定制厂_广州明旺 | 不锈钢法兰-碳钢法兰-法兰盘生产加工厂家-[鼎捷峰]-不锈钢法兰-碳钢法兰-法兰盘生产加工厂家-[鼎捷峰] | 富森高压水枪-柴油驱动-养殖场高压清洗机-山东龙腾环保科技有限公司 | 慢回弹测试仪-落球回弹测试仪-北京冠测精电仪器设备有限公司 | 螺旋丝杆升降机-SWL蜗轮-滚珠丝杆升降机厂家-山东明泰传动机械有限公司 | 注塑模具_塑料模具_塑胶模具_范仕达【官网】_东莞模具设计与制造加工厂家 | 创富网-B2B网站|供求信息网|b2b平台|专业电子商务网站 | 手术室净化厂家-成都做医院净化工程的公司-四川华锐-15年特殊科室建设经验 | 北京宣传片拍摄_产品宣传片拍摄_宣传片制作公司-现像传媒 | 海日牌清洗剂-打造带电清洗剂、工业清洗剂等清洗剂国内一线品牌 海外整合营销-独立站营销-社交媒体运营_广州甲壳虫跨境网络服务 |