线程同步中的While vs If

时间:2018-10-23 14:25:27

标签: java multithreading synchronization thread-synchronization

我有两套代码,我试图依次打印字母和数字。一套使用“ while循环”,另一套使用“ if”。

public class Alphabets {

  public static void main(String[] args) {

          AN an= new AN(false);

          Thread t1=new Thread(new Runnable() {

            @Override
            public void run() {             
                try {                       
                    an.Alpha();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        });              

          Thread t2= new Thread(new Runnable() {                
            @Override
            public void run() {
                try {
                    an.numbers();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }                   
            }
        });                   
          t1.start();
          t2.start();
   }
}

class AN {  
  boolean flag; 
  AN(boolean flag) {
    this.flag=flag;
  }
  synchronized void Alpha() throws InterruptedException {       
    for(char i='A'; i<='Z';i++) {
        while(flag==false) { // I have replaced "while" with "if" in my second code         
          System.out.println(+i);
          notifyAll();
          flag=true;
        }           
        wait();         
    }
  }    
  synchronized void numbers() throws InterruptedException {     
    for(int i=1;i<=26;i++) {            
        while(flag==true) {// I have replaced "while" with "if" in my second code           
          System.out.println(+i);
          notifyAll();
          flag=false;
        }           
        wait();         
    }
  }     
}

通过“ while”循环设置1给出以下输出:

65 1 66 2 67 3 68 4

将2设置为“ if”可得到以下输出:

65 1 67 3 69 5 71 7

请注意,65 66是A,B等的ASCII码。

任何人都可以解释为什么这两个代码是这样的。我无法弄清楚。 请详细解释。

2 个答案:

答案 0 :(得分:0)

答案在spurious wakeup中。这意味着在没有任何人实际调用notify的情况下,任何等待语句都可能自发地唤醒。在这种情况下,for循环又前进了一步,而实际上没有打印任何内容,因为该标志仍处于错误状态。

使用或是否对代码本身没有影响,只是碰巧更频繁地触发实际问题。

解决此问题的方法是循环等待,直到状态实际更改:

for(char i='A'; i<='Z';i++) {
    if(flag==false) {          
      System.out.println(+i);
      notifyAll();
      flag=true;
    } 
    while (flag == true) {    // spurious wakeup prevention      
      wait();         
    }
}

答案 1 :(得分:-1)

while loop 在多线程中是首选,因为它可以防止 spurious wake up ,这意味着wait()方法可以在没有用户线程通知的情况下返回,可能是由 OS scheduler 完成的。在您的情况下,我猜因为spurious wakeup if() condition被跳过,然后又转到wait()