【问题标题】:Multithread - even odd sequence多线程 - 偶奇数序列
【发布时间】:2013-07-12 17:43:09
【问题描述】:

我试图解决一个多线程问题,但在了解它的行为时遇到了困难。

问题是: 有 2 个线程同时消耗 evenodd 数字。我必须引入它们之间的线程通信,以使“消耗”按自然顺序排列。

这是我的代码

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

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

【问题讨论】:

  • 在 SO 上有 许多 重复此作业。这是一个:stackoverflow.com/questions/6017281/… 和另一个 stackoverflow.com/questions/16689449/…
  • @BrianRoach 感谢您的评论。但是我在同一个 Number 实例上执行 notifywait .. 那么它对我不起作用?
  • 仅作记录,调试多线程应用程序并不能保证按照您的预期运行,它可能会一次性(或可能总是)为您提供正确的结果,而不会显示真正的问题。
  • @BrianRoach 虽然老实说我不确定为什么他的代码(与您指向的答案非常相似)不起作用。

标签: java multithreading producer-consumer


【解决方案1】:

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

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

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

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

【讨论】:

  • 这正是问题所在 - 我正在摸不着头脑(并且在循环中使用 notifyAll + 调用 wait 会是个好主意)。
  • 非常感谢.. 我在getOddgetEven 方法中添加了打印语句,效果很好!
【解决方案2】:

notify 选择任何可用的线程。

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

如果有两个以上的线程在等待,您可能会发出“错误”线程的信号。

另外,请注意,您的两个线程可能刚刚在 get(Even|Odd) 中完成而没有等待,导致通知无处可去,具体取决于调度。

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

【讨论】:

  • 感谢@Paul 的想法
【解决方案3】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-26
    • 2011-02-14
    • 1970-01-01
    • 2016-04-25
    • 2014-04-03
    • 1970-01-01
    • 2017-02-06
    相关资源
    最近更新 更多