OCP Question 44, Explanation

Given:

class Jerry extends Thread {
    CyclicBarrier cb;
    public Jerry(CyclicBarrier cb) { this.cb = cb; }
    public void run() {
        try {
        cb.await();
        System.out.println("Jerry running");
        } catch (Exception ex) { }
    }
}

class Tom implements Runnable { //line n1
    public void run() {
        System.out.println("Tom chasing");
    }
}

and the code fragment:

Tom tom = new Tom();
//line n2
Jerry jerry = new Jerry(cb);
jerry.start();

You have been asked to ensure that the run methods of both the Tom and Jerry classes are executed. Which modification meets the requirement?

A. At line n2, insert CyclicBarrier cb = new CyclicBarrier(2, tom);
B. Replace line n1 with class Master extends Thread {
C. At line n2, insert CyclicBarrier cb = new CyclicBarrier(1, tom);
D. At line n2, insert CyclicBarrier cb = new CyclicBarrier(tom);

 

The correct answer is C.

 

The javadoc for CyclicBarrier(int parties, Runnable barrierAction) constructor says it all:

Right now, the code doesn’t even compile because the Jerry(cb) ctor needs a valid cb object, which we have to to create first, therefore option B is immediately out.

Then we have to make sure that both run() methods fire. Okay, how do they work? Let’s make the code executable and see for ourselves:

package host.igor;
import java.util.concurrent.*;

class Jerry extends Thread {
    CyclicBarrier cb;
    public Jerry(CyclicBarrier cb) { this.cb = cb; }
    public void run() {
        try {
        cb.await();
        System.out.println("Jerry running");
        } catch (Exception ex) { }
    }
}

class Tom implements Runnable {
    public void run () {
        System.out.println("Tom chasing");
    }
}

class Cartoon{
    public static void main(String[] args) {
        Tom tom = new Tom();
        CyclicBarrier cb = null;
        Jerry jerry = new Jerry(cb);
        jerry.start();
    }
}

This program compiles and runs successfully; it just doesn’t do anything because after calling start() on jerry, jerry‘s run() invokes await() on a null cb, which throws an NPE, and a silent catch doesn’t let us see anything. Anyway, the program’s intentions should be clear: the jerry thread begins running after main() orders it to start, and then jerry is supposed to wait at the CyclicBarrier. Yes, but what or who he’ll be waiting for? For tom to arrive? That makes no sense because tom‘s not running, not yet, he’ll never arrive. This logic gives us the number of parties to wait at the barrier before the barrier trips: just one. Which means, in effect, that there’ll be no actual waiting: as soon as jerry comes to barrier, the barrier drops.

Now that we saw jerry running, it’s time to make sure tom‘s run() is executed, too. How do we do this? By specifying the barrier action, thus supplying the second and last arg to cb‘s constructor: the action must be performed by tom:

class Cartoon{
    public static void main(String[] args) {
        Tom tom = new Tom();
        CyclicBarrier cb = null;
        CyclicBarrier cb = new CyclicBarrier(1, tom); 
        Jerry jerry = new Jerry(cb);
      jerry.start();
    }
}

The ending scene: Jerry runs up to the barrier, kicks it, the barrier drops with a defeaning noise, and startled Tom bolts forward like crazy… while Jerry remains behind smirking gleefully, jumping and shouting: “Run Tom run! See Tom run!”… Never really liked him, have been always rooting for Tom. Here, let’s teach that little obnoxious overweight 77-year-old rodent some manners:

class Cartoon{
    public static void main(String[] args) {
        Tom tom = new Tom();
        CyclicBarrier cb = new CyclicBarrier(2, tom);   // he-he-he, wait till molds grows on you Jerry
                                                        // 'cause noone's a-coming. Losah
        Jerry jerry = new Jerry(cb);
        jerry.start();
    }
}

Leave Comment

Your email address will not be published.