[Java] 4 Different Solutions w/ Explanation
0. Analysis\nHere we have 3 threads and all we want to achieve is to make sure the 3 threads run in a specific order. To achieve this, we need coordination amon
## 0. Analysis\nHere we have 3 threads and all we want to achieve is to make sure the 3 threads run in a specific order. To achieve this, we need coordination among the threads, which means accessing and managing some common objects/resources. I think the most important point to achieve is about **visibility**: the other threads should be able to know the state change of some commonly accessed objects/values used for the coordination.\n\nTo achieve this, we can either use some ready-to-use utility classes in `java.util.concurrent` package, or managing the visibility and status with some Java language features. \n\nBelow are a few possible solutions:\n\n## 1.  The volatile keyword\nIn summary, the Java `volatile` keyword **guarantees visibility of changes** to variables across threads (from [this article](http://tutorials.jenkov.com/java-concurrency/volatile.html)), and that\'s literally all we need here so that when` first()` and `second()` increment the `flag` value, the next methods (in other threads) are able to capture the updated value so that the execution condition can be met (i.e., the `while` loop will exit).\n\nSo we have the solution like below:\n```\nclass Foo {\n    private static volatile int flag;\n    \n    public Foo() {\n        flag = 1;\n    }\n\n    public void first(Runnable printFirst) throws InterruptedException {\n        // printFirst.run() outputs "first". Do not change or remove this line.\n        printFirst.run();\n        flag++; // flag that it\'s ready for second() to run\n    }\n\n    public void second(Runnable printSecond) throws InterruptedException {\n        while(flag != 2){} // wait until the flag turns 2\n        // printSecond.run() outputs "second". Do not change or remove this line.\n        printSecond.run();\n        flag++; // flag that it\'s ready for third() to run\n    }\n\n    public void third(Runnable printThird) throws InterruptedException {\n        while(flag != 3){} // wait until the flag turns 3\n        // printThird.run() outputs "third". Do not change or remove this line.\n        printThird.run();\n    }\n}\n```\n\n## 2. AtomicInteger\nThe `AtomicXXX` classes are located in `java.util.concurrent` package. The main feature for those classes is that they ensure ***atomic actions*** on the instances, which in simple terms means that only a single thread will be able to access the object at a time, and the updated value will be visible to other threads. It\'s achieved using CAS (compare and swap) strategy.\n\nSo the solution is like below:\n```\nclass Foo {\n    private static AtomicInteger flag;\n    \n    public Foo() {\n        flag = new AtomicInteger(1);\n    }\n\n    public void first(Runnable printFirst) throws InterruptedException {\n        // printFirst.run() outputs "first". Do not change or remove this line.\n        printFirst.run();\n        flag.incrementAndGet(); // flag that it\'s ready for second() to run\n    }\n\n    public void second(Runnable printSecond) throws InterruptedException {\n        while(flag.get() != 2){} // wait until the flag value turns 2\n        // printSecond.run() outputs "second". Do not change or remove this line.\n        printSecond.run();\n        flag.incrementAndGet();  // flag that it\'s ready for third() to run\n    }\n\n    public void third(Runnable printThird) throws InterruptedException {\n        while(flag.get() != 3){} // wait until the flag value turns 3\n        // printThird.run() outputs "third". Do not change or remove this line.\n        printThird.run();\n    }\n}\n```\n\n## 3. Semaphore\nA `Semaphore` manages a set of  virtual  permits; the  initial number of permits  is passed to the Semaphore constructor. Activities can `acquire` permits (as long as some remain) and `release` permits when they are done with them. If no permit is available, acquire blocks until one is (or until interrupted or the operation times out). The `release` method returns a permit to the semaphore. (from the book [Java Concurrency in Practice](https://www.amazon.com/Java-Concurrency-Practice-Brian-Goetz/dp/0321349601))\n\nSo we use 2 Semaphore objects, one to control when the` second()` method can proceed, the other to control when the `third()` method can proceed. Solution is like below:\n\n```\nclass Foo {\n    private static Semaphore sem2;\n    private static Semaphore sem3;\n    \n    public Foo() {\n        sem2 = new Semaphore(0);\n        sem3 = new Semaphore(0);\n    }\n\n    public void first(Runnable printFirst) throws InterruptedException {\n        // printFirst.run() outputs "first". Do not change or remove this line.\n        printFirst.run();\n        sem2.release(); // release a sem2 permit so that second() can proceed\n    }\n\n    public void second(Runnable printSecond) throws InterruptedException {\n        sem2.acquire();  // will block until any Semaphore permit is available\n        // printSecond.run() outputs "second". Do not change or remove this line.\n        printSecond.run();\n        sem3.release(); // release a sem3 permit so that third() can proceed\n    }\n\n    public void third(Runnable printThird) throws InterruptedException {\n       sem3.acquire(); // will block until any Semaphore permit is available\n        // printThird.run() outputs "third". Do not change or remove this line.\n        printThird.run();\n    }\n}\n```\n\n## 4. CountDownLatch\n`CountDownLatch` is another type of synchronizer. It can delay the progress of threads until it reaches its terminal state, i.e., when it counts down to 0. \n\nMuch like solution 3 with `Semaphore`, we use 2 `CountDownLatch` instances. One to control when the` second()` method can proceed, the other to control when the `third()` method can proceed. Solution is like below:\n\n```\nclass Foo {\n    private static CountDownLatch latch2;\n    private static CountDownLatch latch3;\n    \n    public Foo() {\n        latch2 = new CountDownLatch(1);\n        latch3 = new CountDownLatch(1);\n    }\n\n    public void first(Runnable printFirst) throws InterruptedException {\n        // printFirst.run() outputs "first". Do not change or remove this line.\n        printFirst.run();\n        latch2.countDown(); // count down latch2 to 0 so that second() can proceed\n    }\n\n    public void second(Runnable printSecond) throws InterruptedException {\n        latch2.await(); // wait until latch2 counts down to 0\n        // printSecond.run() outputs "second". Do not change or remove this line.\n        printSecond.run();\n        latch3.countDown(); // count down latche to 0 so that third() can proceed\n    }\n\n    public void third(Runnable printThird) throws InterruptedException {\n       latch3.await(); // wait until latch3 counts down to 0\n        // printThird.run() outputs "third". Do not change or remove this line.\n        printThird.run();\n    }\n}\n```\n\nHope it helps!
[]