2013-07-12 49 views
2

我正试图解决一个多线程问题,我正面临着难以了解其行为。多线程 - 甚至是奇数序列

的问题是: 有2个线程,其同时消耗甚至奇数号码。我必须介绍它们之间的线程通信,以自然排序的方式使“消耗”

这里是我的代码

public class EvenOddDemo { 

    public static void main(String[] args) { 
     Number n = new Number(); 
     EvenThread et = new EvenThread(n); 
     OddThread ot = new OddThread(n); 
     et.start(); 
     ot.start(); 
    } 

} 

class EvenThread extends Thread { 

    private Number number; 

    public EvenThread(Number number) { 
     this.number = number; 
    } 

    @Override 
    public void run() { 
     for(int i=0; i<5; i++) { 
      System.out.println(number.getEven()); 
     } 
    } 


} 

class OddThread extends Thread { 

    private Number number; 

    public OddThread(Number number) { 
     this.number = number; 
    } 

    @Override 
    public void run() { 
     for(int i=0; i<5; i++) { 
      System.out.println(number.getOdd()); 
     } 
    } 


} 

class Number { 

    private int currentEven = 0; 

    private int currentOdd = 1; 

    private volatile String last = "odd"; 

    public synchronized int getEven() { 
     if("even".equals(last)) { 
      try { 
       wait(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
     int i = currentEven; 
     last = "even"; 
     currentEven +=2; 
     notify(); 
     return i; 
    } 

    public synchronized int getOdd() { 
     if("odd".equals(last)) { 
      try { 
       wait(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
     int i = currentOdd; 
     last = "odd"; 
     currentOdd +=2; 
     notify(); 
     return i; 
    } 
} 

和输出

0 
2 
1 
3 
4 
5 
7 
6 
8 
9 

但是,当我调试的代码,它以正确的顺序打印号码。因此我无法弄清楚我错过了什么。请帮帮我。预先感谢您为此主题准备的时间。

+1

有此功课SO的*众多*的DUP。这里是一个:http://stackoverflow.com/questions/6017281/odd-even-number-printing-using-thread?rq=1和另一个http://stackoverflow.com/questions/16689449/printing-even-and-奇数使用两线程在Java?rq = 1 –

+0

@BrianRoach感谢您的评论。然而,我正在做'notify'和'wait'在相同的'Number'实例..所以它怎么不适合我? – sanbhat

+2

只是为了记录,调试多线程应用程序并不能保证您的行为正常,它可能会给您一次(或者可能总是)正确的结果,并且永远不会显示真正的问题。 –

回答

5

据我所看到的,没有什么阻止这种情况的发生,解释为什么2在你的输出1之前显示:

OddThread  EvenThread 
---------- ---------- 
gets odd 
       gets even 
       prints even 
prints odd 

锁定,因此需要将整个序列围绕“获取/打印”。

您会注意到,在输出中,您永远不会“相差两位数”。

+1

这正是问题 - 我抓我的头(并使用notifyAll +在循环中调用等待将是一个好主意)。 – assylias

+0

非常感谢..我在'getOdd','getEven'方法中添加了print语句,并且它非常完美! – sanbhat

2

notify选择任何可用的线程。

的选择是任意的,如果有两个以上的线程在等待,你可能意味着将“错误”的线程发生在执行

的自由裁量权。

另外,请注意,您的两个线程都可能在刚刚完成时得到(偶数|偶数),而且两个都没有等待,导致通知无法执行,具体取决于调度。

您需要更加严格以确保排序。也许两把锁,偶数和奇数都会有帮助。

+0

感谢@保尔为你的想法 – sanbhat

0

您需要在getEven和getOdd函数中打印数字并通知其他线程。 但你通知并打印数量,所以的NotI 修改后的代码之间:

public class ThreadExp { 

    public static void main(String[] args) { 
     Number n = new Number(); 
     EvenThread et = new EvenThread(n); 
     OddThread ot = new OddThread(n); 
     et.start(); 
     ot.start(); 
    } 

} 

class EvenThread extends Thread { 

    private Number number; 

    public EvenThread(Number number) { 
     this.number = number; 
    } 

    @Override 
    public void run() { 
     for (int i = 0; i < 10; i++) { 
      number.getEven(); 
     } 
    } 

} 

class OddThread extends Thread { 

    private Number number; 

    public OddThread(Number number) { 
     this.number = number; 
    } 

    @Override 
    public void run() { 
     for (int i = 0; i < 10; i++) { 
      number.getOdd(); 
     } 
    } 

} 

class Number { 

    private int currentEven = 0; 

    private int currentOdd = 1; 

    private StringBuilder odd; 
    private StringBuilder even; 
    private StringBuilder last; 

    { 
     odd = new StringBuilder("odd"); 
     even = new StringBuilder("even"); 
     last = odd; 
    } 

    public synchronized void getEven() { 
     if (last == even) { 
      try { 
       //System.out.println("inside if in even--->" +Thread.currentThread()); 
       wait(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
     //System.out.println("out of if in even--> " + Thread.currentThread()); 
     int i = currentEven; 
     last = even; 
     currentEven += 2; 
     System.out.println(i); 
     notify(); 
     return; 
    } 

    public synchronized void getOdd() { 
     if (last == odd) { 
      try { 
       //System.out.println("inside if in odd--->" +Thread.currentThread()); 
       wait(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
     //System.out.println("out of if in odd--> " + Thread.currentThread()); 

     int i = currentOdd; 
     last = odd; 
     currentOdd += 2; 
     System.out.println(i); 
     notify(); 
     return; 
    } 
}