多线程 - 甚至奇数序列

时间:2013-07-12 17:43:09

标签: java multithreading producer-consumer

我试图解决多线程问题,但我很难了解其行为。

问题是: 有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

但是当我调试代码时,它会以正确的顺序打印数字。因此,我无法弄清楚我错过了什么。请帮我。提前感谢您抽出这个帖子的时间。

3 个答案:

答案 0 :(得分:5)

据我所知,没有什么可以防止这种情况发生,解释了为什么2在输出1之前显示:

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

锁定因此需要围绕整个序列“get / print”。

你会注意到你的输出中你永远不会“分开两个数字”。

答案 1 :(得分:2)

notify选择任何可用的帖子。

  

选择是任意的,由实施决定

如果有两个以上的线程在等待,则可能是“错误”线程的信号。

另外,请注意,两个线程都可以在get(偶数| Odd)中完成而不等待,导致通知无处可寻,具体取决于调度。

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

答案 2 :(得分: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;
    }
}