简体   繁体   English

带有控制线程的奇偶打印数字线程

[英]Odd even printing number threads with a control thread

I wrote below program in which even thread would print even numbers whereas odd thread would print odd numbers.我写了下面的程序,其中even线程将打印偶数,而odd线程将打印奇数。 In addition to the odd and even threads, I created a control thread, which decides if a number is odd or even and sets flag appropriately.除了奇数和偶数线程之外,我还创建了一个control线程,它决定一个数字是奇数还是偶数,并适当地设置标志。 Based on the flag which control thread sets, either odd or even thread will get chance to print.根据控制线程设置的标志, oddeven线程都有机会打印。

I am using an array as source.我使用数组作为源。 The control thread increments the index so odd or even thread can retrieve the number from array and print.控制线程增加index ,因此奇数或偶数线程可以从数组中检索数字并打印。

The below is the complete code, with comments are well.下面是完整的代码,注释很好。


package com.example.practice;


public class OddEvenDemoVer2 {

    // Since all of these variable are used in a synchronized block, I think we
    // don't need them to be as volatile, as synchronized enforces
    // memory-barrier and hence all thread would see latest values.

    static boolean printEven = false;
    static boolean printingDone = false;
    static int index = 0;

    static volatile boolean stop = false;

    static volatile boolean oddThreadStarted = false;
    static volatile boolean evenThreadStarted = false;

    public static void main(String[] args) throws InterruptedException {

        Object _controlLock = new Object();
        Object _indexControlLock = new Object();

        int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

        class ControlThread implements Runnable {

            @Override
            public void run() {

                // Wait for proper initialization of odd and even threads.
                while (!oddThreadStarted && !evenThreadStarted) {
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                for (; !stop;) {

                    // This is to make sure that we give chance to OddThread or
                    // EvenThread to print the values.

                    // Here, we are only setting the flag which thread should
                    // print the number, the advancing of index is done in
                    // another block.
                    synchronized (_controlLock) {

                        if (arr[index] % 2 == 0) {
                            printEven = true;
                        }
                        else {
                            printEven = false;
                        }
                        _controlLock.notifyAll();
                    }

                    // This is to make sure we advance index only when printing
                    // has been done either by OddThread or EvenThread
                    synchronized (_indexControlLock) {
                        while (printingDone != true) {
                            try {
                                _indexControlLock.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        index++;
                        if (index > 9) {
                            stop = true;
                        }
                    }
                }
            }
        }

        class EvenPrintingThread implements Runnable {

            @Override
            public void run() {
                evenThreadStarted = true;

                // Loop until stop is signaled by ControlThread
                for (; !stop;) {

                    synchronized (_controlLock) {
                        while (printEven != true) {
                            try {
                                _controlLock.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        System.out.println("Even printing thread --> " + arr[index]);

                        // This is to signal control thread that printing has
                        // been done and now index can be advanced.
                        synchronized (_indexControlLock) {
                            printingDone = true;
                            _indexControlLock.notify();
                        }
                    }
                }
            }
        }

        class OddPrintingThread implements Runnable {

            @Override
            public void run() {
                oddThreadStarted = true;

                // Loop until stop is signaled by ControlThread
                for (; !stop;) {

                    synchronized (_controlLock) {
                        while (printEven != false) {
                            try {
                                _controlLock.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }

                        System.out.println("Odd printing thread --> " + arr[index]);

                        // This is to signal control thread that printing has
                        // been done and now index can be advanced.
                        synchronized (_indexControlLock) {
                            printingDone = true;
                            _indexControlLock.notify();
                        }
                    }
                }
            }
        }

        Thread controlThread = new Thread(new ControlThread());

        controlThread.start();

        Thread evenThread = new Thread(new EvenPrintingThread());
        Thread oddThread = new Thread(new OddPrintingThread());

        evenThread.start();
        oddThread.start();

        Thread.sleep(1000000L);
    }
}

I expected this program will work, however it is behaving erratically.我预计这个程序会起作用,但是它的行为不正常。 For example, one of the output is:例如,output 之一是:

Odd printing thread --> 1
Odd printing thread --> 1

Odd printing thread --> 1
Odd printing thread --> 1

...

Odd printing thread --> 1
Odd printing thread --> 1
Odd printing thread --> 1
Odd printing thread --> 10
Odd printing thread --> 10
Odd printing thread --> 10
Odd printing thread --> 10

I saw online some other ways in which similar problem can be solved, however, when I started on this (without looking for ready made solution online), the above approach came to my mind.我在网上看到了一些可以解决类似问题的其他方法,但是,当我开始这样做时(没有在网上寻找现成的解决方案),我想到了上述方法。 I don't want to abandon simply because it isn't working.我不想仅仅因为它不起作用而放弃。 I debugged, but didn't got a clarity as to what might be wrong in this approach.我进行了调试,但并不清楚这种方法可能有什么问题。

What am I missing?我错过了什么?

EDIT编辑

Attaching the screen shot in which shows two threads "owning" same object id.附上屏幕截图,其中显示两个线程“拥有”相同的 object id。

调试截图

Depending on the expected behavior, it only needs one or two changes.根据预期的行为,它只需要一两次更改。

The output that you're seeing is not wrong.你看到的output没有错。 Your printingDone will never be set back to false , so the controller thread will happily keep incrementing your index once it gets the chance.您的printingDone永远不会被设置回false ,因此 controller 线程一旦有机会就会很高兴地继续增加您的索引。 The notifyAll() method will wake up suspended odd/even threads, but all threads using the same lock are still competing for synchronization. notifyAll()方法会唤醒挂起的奇/偶线程,但所有使用同一个锁的线程仍在竞争同步。 My guess is that the controller thread finishes the increment fast enough to compete and therefore you have a race condition with unreliable output.我的猜测是 controller 线程完成增量足够快以竞争,因此你有一个不可靠的 output 的竞争条件。

If you want at least one line for each array element, just set printingDone back to false after you incremented the index in the controller thread:如果您希望每个数组元素至少有一行,只需在 controller 线程中增加索引后将printingDone设置回false

                    index++;
                    if (index > 9) {
                        stop = true;
                    }
                    printingDone = false;

If you feel like you should only get one output per value, it also makes sense to suspend your odd/even threads whenever printingDone is set to true :如果您觉得每个值应该只获得一个 output ,那么只要printingDone设置为true ,暂停奇数/偶数线程也是有意义的:

                    while (printingDone == true || printEven != true) { // or printEven == true for the odd printer
                        try {
                            _controlLock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }

Edit: Oh, and the reason why you're seeing even numbers printed by the odd thread is probably due to the fact that the odd thread acquires the controller lock after the index increment, but before the controller gets the chance to update printEven .编辑:哦,你看到奇数线程打印偶数的原因可能是因为奇数线程在索引增量之后获取 controller 锁,但在 controller 有机会更新printEven Perhaps you should think of a way to both increment and update the boolean in the same code block.也许您应该想办法在同一代码块中增加和更新 boolean。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM