In synchronized methods, a thread is allowed to keep running until it either leaves the method or it calls wait(). No other thread can run until this happens.
Threads can be in one of 4 states:
Currently running.
Waiting to obtain the monitor so it can run (This is a different type of blocking.)
Blocked, waiting to be notified. (called wait())
Exited, will never run again.
In the standard model, the scheduler is able to move a thread from 1 to 2 and then another from 2 to 1 whenever it pleases. But synchronized prevents this from happening.
……
just need to ensure that:
thread NEVER gives up the monitor (i.e. calls wait()) when it was actually its turn to run.
notifyAll() is always called whenever an important change is made, ensuring that everybody will get their chance to see it. This tells them they can run as soon as they can get that monitor.
class FizzBuzz { private int n; private Semaphore sem, sem3, sem5, sem15; public FizzBuzz(int n) { this.n = n; sem = new Semaphore(1); sem3 = new Semaphore(0); sem5 = new Semaphore(0); sem15 = new Semaphore(0); }
// printFizz.run() outputs "fizz". public void fizz(Runnable printFizz) throws InterruptedException { for (int i = 3; i <= n; i += 3) { sem3.acquire(); printFizz.run(); if ((i + 3) %5 == 0) i += 3; sem.release(); } }
// printBuzz.run() outputs "buzz". public void buzz(Runnable printBuzz) throws InterruptedException { for (int i = 5; i <= n; i += 5) { sem5.acquire(); printBuzz.run(); if ((i + 5) %3 == 0) i += 5; sem.release(); } }
// printFizzBuzz.run() outputs "fizzbuzz". public void fizzbuzz(Runnable printFizzBuzz) throws InterruptedException { for (int i = 15; i <= n; i += 15) { sem15.acquire(); printFizzBuzz.run(); sem.release(); } }
// printNumber.accept(x) outputs "x", where x is an integer. public void number(IntConsumer printNumber) throws InterruptedException { for (int i = 1; i <= n; ++i) { sem.acquire(); if (i % 15 == 0) sem15.release(); else if (i %3 == 0) sem3.release(); else if (i %5 == 0) sem5.release(); else { printNumber.accept(i); sem.release(); } } } }