Easy Solution || 2 Approaches || monitor || lock
Intuition\n\n---\n\n\nHere the problem states that if the input passed is a number n = 5, we need to print all the numbers from 1 to n, each number should be se
# Intuition\n\n---\n\n\nHere the problem states that if the input passed is a number n = 5, we need to print all the numbers from 1 to n, each number should be separated by a 0.\n(n=5 => 0102030405)\nWe need to implement three functions, zero(), even() and odd() to print each number from this series 0102030405.\n\n# Approach\n\n---\n\n\nHere in this approach we are using synchronised block.\nwe are using the concept of monitor & in java each object can act as a monitor and by default it inherits three handy method await(), notify(), notifyAll().\n\nso when we wait for some condition, current thread waits until another thread changes the values and notify all the sleeping thread.\n\nwe resume tasks only if the condition fails.\n\n> 1. before printing each value we need to print 0, so we can maintain a boolean that we can toggle after printing the value, such that it can be printed alternatively.\n> 2. we check for condition if even & odd and print if the current value is event & odd respectively.\n> 3. after changing any shared variable on which the thread is waiting we notify all the waiting thread to recheck the condition.\n\n# Approach 1\n\n---\n\n\n\n```\nclass ZeroEvenOdd {\n    private int n;\n    private boolean zeroPrinted;\n    private int currentNumber;\n\n    public ZeroEvenOdd(int n) {\n        this.n = n;\n        this.zeroPrinted = false;\n        this.currentNumber = 1;\n    }\n\n    // printNumber.accept(x) outputs "x", where x is an integer.\n    public void zero(IntConsumer printNumber) throws InterruptedException {\n        \n        while(currentNumber <= n)\n        synchronized(this) {\n            while(zeroPrinted == true)\n                wait();\n\n            if(currentNumber <= n) {\n                printNumber.accept(0); \n            }  \n            zeroPrinted = true;\n            notifyAll();\n        \n        }\n    }\n\n    public void even(IntConsumer printNumber) throws InterruptedException {\n\n            while(currentNumber <= n)\n            synchronized(this) {\n                while(currentNumber % 2 == 1 || zeroPrinted == false) \n                    wait();\n\n                if(currentNumber <= n) {\n                    printNumber.accept(currentNumber); \n                }      \n                zeroPrinted = false;\n                currentNumber++;\n                notifyAll();\n            }\n        \n        \n    }\n\n    public void odd(IntConsumer printNumber) throws InterruptedException {\n        \n            while(currentNumber <= n)\n            synchronized(this) {\n                while(currentNumber % 2 == 0 || zeroPrinted == false) \n                wait();\n\n            if(currentNumber <= n) {\n                printNumber.accept(currentNumber); \n            }    \n            zeroPrinted = false;\n            currentNumber++;  \n            notifyAll();\n            }\n        }\n        \n}\n```\n\nSimilar to above approach just that we are different syntax to achive the same objective.\ni am going to map equivalents from the first approach\n```\nwait() --> condition.await()\nnotify() --> condition.signal()\nnotifyAll() --> condition.signalAll()\n\nthere is a condition Class offered by Lock on which we \ncan call the above methods\nit makes sense as we are waiting for a condition to be fulfilled.\n\n```\n\n# Approach 2\n\n---\n\n\n```\nclass ZeroEvenOdd {\n    private int n;\n    private boolean zeroPrinted;\n    private int currentNumber;\n    private Lock lock;\n    private Condition condition;\n\n    public ZeroEvenOdd(int n) {\n        this.n = n;\n        this.zeroPrinted = false;\n        this.currentNumber = 1;\n        lock = new ReentrantLock();\n        condition = lock.newCondition();\n    }\n\n    // printNumber.accept(x) outputs "x", where x is an integer.\n    public void zero(IntConsumer printNumber) throws InterruptedException {\n        \n        while(currentNumber <= n) {\n        lock.lock();\n            while(zeroPrinted == true)\n                condition.await();\n            \n            // we are checking again as the while loop is outside synchronized block \n            // so thread can get context switched\n            if(currentNumber <= n) {\n                printNumber.accept(0); \n            }  \n            zeroPrinted = true;\n            condition.signalAll();\n        \n        lock.unlock();\n        }\n    }\n\n    public void even(IntConsumer printNumber) throws InterruptedException {\n\n            while(currentNumber <= n) {\n            lock.lock();\n                while(currentNumber % 2 == 1 || zeroPrinted == false) \n                    condition.await();\n\n                // we are checking again as the while loop is outside synchronized block \n                // so thread can get context switched\n                if(currentNumber <= n) {\n                    printNumber.accept(currentNumber); \n                }      \n                zeroPrinted = false;\n                currentNumber++;\n                condition.signalAll();\n            lock.unlock();\n\n            }\n        \n        \n    }\n\n    public void odd(IntConsumer printNumber) throws InterruptedException {\n        \n            while(currentNumber <= n) {\n            lock.lock();\n                while(currentNumber % 2 == 0 || zeroPrinted == false) \n                    condition.await();\n\n            // we are checking again as the while loop is outside synchronized block \n            // so thread can get context switched\n            if(currentNumber <= n) {\n                printNumber.accept(currentNumber); \n            }    \n            zeroPrinted = false;\n            currentNumber++;  \n                condition.signalAll();\n\n            lock.unlock();\n\n            }\n        }\n        \n}\n```
['Concurrency', 'Java']