亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

為什么這個多線程程序會陷入無限循環?

為什么這個多線程程序會陷入無限循環?

慕碼人8056858 2021-11-03 16:49:07
下面的程序是一個簡單的線程程序。由于某種我無法想象的原因,它在兩個線程中同時陷入了生產()和消費()方法的無限循環中。它產生幾次輸出,然后在控制臺上沒有輸出。所以我認為它陷入了循環。我的問題是,由于循環取決于valueSetItem 類的同一對象的標志值,valueSet因此不能同時為真和假。因此,produce() 或 cosume() 方法的循環都應該為 false,并且輸出的打印應該繼續。但這里不會發生這種情況。那么,如果條件取決于一次只能取真或假的標志變量,為什么它會卡在 while 循環中呢?class Item{    boolean valueSet = false ;     int item = 0 ;     public  void consume(){        while(!valueSet) ;        System.out.println("Consumed : "  + item ) ;         valueSet = false ;    }    public  void produce(int n ){        while(valueSet);        item = n ;        System.out.println("Produced : "  + item ) ;         valueSet = true ;    } }class Producer implements Runnable{ Item item ; Producer(Item itemobj){     item = itemobj ;  } public void run(){     while(true){         System.out.println("\nProducing ....") ;      item.produce((int)Math.random()*100) ;      } }}class Consumer implements Runnable{    Item item  ;    Consumer(Item itemobj){item = itemobj ; }    public void run(){        while(true){            System.out.println("\nConsuming !") ;        item.consume() ;         }    }}class Main{    public static void main(String[] args) {        Item item = new Item() ;        Thread consumer = new Thread(new Consumer(item)) ;         Thread producer = new Thread(new Producer(item)) ;        System.out.println("\nStarted producer and consumer threads : ") ;         consumer.start() ;         producer.start() ;     }}更新 :當while(valueSet)一個線程卡在無限循環中時,不應該while(!valuSet)跳出循環并翻轉valueSet? 這會反過來導致while(valueSet)跳出循環嗎?根據某些答案,似乎在while(valueSet)卡住時,另一個線程以某種方式無法訪問valueSet。我不明白這是怎么回事。請解釋你的答案。我看到使用volatileforvalueSet會修復它,但我無法理解如何不使用它。即使它依賴于一個valueSet不能同時為真和假的標志,它也會導致無限循環。
查看完整描述

3 回答

?
嚕嚕噠

TA貢獻1784條經驗 獲得超7個贊

基本上,您在這里嘗試做的是valueSet用作布爾標志來同步Consumer和Producer-- 使它們依次工作。真的,valueSet只能在一瞬間是真的或假的;然而,這不是兩個線程(消費者和生產者)如何看待它。


我們知道在 Java 中,對象存儲在堆上;那就是所謂的主存。但是,對于每個線程,出于性能考慮,對所用對象的引用都保存在特定于線程的緩存中。如在這里,Producer和Consumer共享一個Item被存儲在堆上對象; 該字段item.valueSet可能被每個線程緩存。


 _______________    ______________  

 |   Consumer    |  |   Producer   |  

 |   _________   |  |   _________  |  

 |  |         |  |  |  |         | |  

 |  | Cache1  |  |  |  |  Cache2 | |  

 |  | valueSet|  |  |  | valueSet| |

 |  |_________|  |  |  |_________| |  

 |_______________|  |______________|

           | |              | |

           | |              | |

          _|_|______________|_|__

         |                       |

         |      MAIN MEMORY      | 

         |      valueSet         | 

         |_______________________|

例如,當Consumer更改valueSet為 時false,它可能會也可能不會將新值刷新到主內存;類似地,當Producer檢查時valueSet,它可能會也可能不會嘗試從主內存中讀取最新值。這就是volatile關鍵字發揮作用的地方。當您設置valueSet為 時volatile,它確保兩個線程向/從主內存寫入/讀取最新值。


請注意,上面的總結基本上被稱為JVM 內存模型。它是一組規則,用于定義多線程情況下 JVM 的行為。


如果您嘗試更改代碼的以下部分:


    **volatile** boolean valueSet = false ; 

    **volatile** int item = 0 ;

    ...

    item.produce((int)(Math.random()*100)) ; // added parenthesis

您將看到以下輸出:


Started producer and consumer threads : 


Consuming !


Producing ....

Produced : 83


Producing ....

Consumed : 83


Consuming !

Produced : 54


Producing ....

Consumed : 54


Consuming !

Produced : 9


Producing ....

Consumed : 9


Consuming !

Produced : 23


Producing ....

Consumed : 23


查看完整回答
反對 回復 2021-11-03
?
阿晨1998

TA貢獻2037條經驗 獲得超6個贊

首先,您需要創建共享變量volatile。

允許線程將其局部變量放在寄存器中,所以是的,一個線程可以將其valueSet視為 false,而另一個線程可以將其視為true. 同時。使變量volatile強制每次都從內存中讀取。

但是,這并不能保證代碼沒有其他問題。同步可能很棘手。但是研究volatile以克服最可能的原因。


查看完整回答
反對 回復 2021-11-03
?
桃花長相依

TA貢獻1860條經驗 獲得超8個贊

ü應該設置valueSetvolatile使兩個線程變量可見。


查看完整回答
反對 回復 2021-11-03
  • 3 回答
  • 0 關注
  • 274 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號