【问题标题】:Printing Odd and Even number using 2 threads?使用 2 个线程打印奇数和偶数?
【发布时间】:2013-09-03 14:37:03
【问题描述】:

我已经尝试过这段代码。但是在打印 0 之后,它什么也不打印。 我认为它是由于某些锁定而阻塞的。

public class EvenOdd implements Runnable {
    private Object o = new Object();
    private volatile int i = 0;

    public void run() {
        try {
            System.out.println();
            if ( Thread.currentThread().getName().equals( "Even")) {
                printEven();
            } else {
                printOdd();
            }
        } catch ( Exception ee) {
            ee.printStackTrace();
        }
    }

    private void printEven() throws InterruptedException {
        while ( true) {
            synchronized ( o) {
                while ( this.i % 2 == 0) {
                    o.wait();
                }
                System.out.println( Thread.currentThread().getName() + i);
                i++;
                o.notify();
            }
        }
    }

    private void printOdd() throws InterruptedException {
        while ( true) {
            synchronized ( o) {
                while ( this.i % 2 != 0) {
                    o.wait();
                }
                System.out.println( Thread.currentThread().getName() + i);
                i++;
                o.notify();
            }
        }
    }
}

我的测试类:

EvenOdd x = new EvenOdd();
        new Thread(x,"Even").start();
        new Thread(x,"Odd").start();

我哪里错了? 谢谢。

P.S : 我知道这种问题已经被问过很多次了,但我想自己尝试一下。

【问题讨论】:

    标签: java multithreading locking synchronized runnable


    【解决方案1】:

    我猜你是;

    • 使用一个 Runnable 但两者都认为它们是偶数,即它们都看到第一个值 0
    • printEven 必须等待奇数,而 printOdd 必须等待偶数

    编辑:运行代码后,OP 修复了代码,它会打印

    0
    1
    

    正如预期的那样。它有时可能会随机打印 0 和 0,因为第一次检查奇数/偶数不同步。

    【讨论】:

    • 我已经添加了测试类。
    • @Raj 所以有一个建议适用;)。
    • 你说的是我的 printEven 方法。我应该将条件更改为while(this.i % 2 == 0){
    • @Raj 并更改 printOdd。
    • 我做到了。它工作正常。我可以通过给线程命名来决定哪个是奇数甚至是奇数。在问题中查看我更新的代码。查看我的运行方法和测试类。
    【解决方案2】:

    这是一个简单的死锁:

    线程 1 等待某人通知锁。线程 2 等待某人通知同一个锁。

    由于没有人访问过o.notify();,因此什么也没有发生。

    i在两个线程都启动时为0,所以都先调用printEven()。现在,当这种情况发生时,两个线程将在下一轮调用printOdd()

    【讨论】:

    • 我可以在哪里更改以消除死锁?
    • 你是说两个线程都进入第一个 printEven() 循环?
    • 是的。我建议你拿一张大纸画一张线图。用代币或硬币来表达状态(谁有锁,谁等待锁,i的值是多少)并模拟过程。
    【解决方案3】:

    基本概念是当一个线程正在运行时,另一个必须等​​待。一旦线程打印了值,它必须等到另一个线程打印。这是通过使用等待/通知机制来实现的。

    当奇数线程完成打印值时,它会通知等待线程(偶数线程),偶数线程准备好运行,但会等待奇数线程释放锁。现在奇数线程调用 locker 对象上的 wait 以便它释放锁并进入等待状态。此时,唯一等待locker对象锁的线程是Even线程并且它运行。这个过程交替进行。

    public class Test {
        public static void main(String[] args) {
            Object locker = new Object();
            Thread t1 = new Thread(new OddWorker(locker));
            Thread t2 = new Thread(new EvenWorker(locker));
            t1.start();
            t2.start();
    
        }
    }
    
    class OddWorker implements Runnable {
        private Object locker;
        private int number = 1, count = 1;
    
        OddWorker(Object locker) {
            this.locker = locker;
        }
    
        @Override
        public void run() {
            synchronized (locker){
                do {
                    try {
                        System.out.println(Thread.currentThread().getName() + ": " + number);
                        number += 2;
                        locker.notify();
                        locker.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } while(++count < 11);
                locker.notify();
            }
        }
    }
    
    class EvenWorker implements Runnable {
        private Object locker;
        private int number = 2, count = 1;
    
        EvenWorker(Object locker) {
            this.locker = locker;
        }
    
        @Override
        public void run() {
            synchronized (locker){
                do {
                    try {
                        System.out.println(Thread.currentThread().getName() + ": " + number);
                        number += 2;
                        locker.notify();
                        locker.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                } while(++count < 11);
            }
        }
    }
    

    【讨论】:

    • 请务必记住,我们希望得到具体解决所提问题的答案。如果问题中有代码,您的答案应该解决该代码本身。
    猜你喜欢
    • 1970-01-01
    • 2011-08-26
    • 2013-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-06
    • 2021-10-15
    • 1970-01-01
    相关资源
    最近更新 更多