It prints usually E-M-A-N-E-M-A-N, but it can be different. How do I make sure that it always prints the desired result?
Without taking any additional steps, the output will vary each time. The first thread (t1) runs as quickly as it can, and the thread has no awareness that there maybe other instances of the Print Runnable.
To make sure it always prints the desired result, you need the threads to coordinate somehow. At a high level, the logic would look something like:
- print a single letter ("E" on first pass through the loop, given input "NAME")
- wait for all other threads to also print their letter – the correct way to do this is with one of several built-in synchronization options
- once all threads agree that it's time to proceed, they can each proceed
A few options for how to proceed: use a CyclicBarrier or a Phaser.
Here's an example showing how to solving this by using a phaser.
First, this is the class for each thread. In the constructor, it accepts a Phaser, a List<String> (where each thread will add output), and the string text itself (ex: "NAME").
class CoordinatedRunnable implements Runnable {
private final Phaser phaser;
private final List<String> outputBuffer;
private final String text;
CoordinatedRunnable(Phaser phaser, List<String> output, String text) {
this.text = text;
this.phaser = phaser;
this.outputBuffer = output;
phaser.register();
new Thread(this).start();
}
@Override
public void run() {
for (int i = text.length() - 1; i >= 0; i--) {
outputBuffer.add(String.valueOf(text.charAt(i)));
phaser.arriveAndAwaitAdvance();
}
phaser.arriveAndDeregister();
}
}
Here is code for the caller, using text "NAME" and creating 2 threads coordinated by the same phaser.
Phaser phaser = new Phaser();
phaser.register();
List<String> outputBuffer = Collections.synchronizedList(new ArrayList<>());
String text = "NAME";
for (int i = 0; i < 2; i++) {
new CoordinatedRunnable(phaser, outputBuffer, text);
}
// main loop advances through each phase, along with each worker thread
for (int i = 0; i < text.length(); i++) {
phaser.arriveAndAwaitAdvance();
}
// reach here only when everyone is done with all phases
// print everything in the buffer, except for the last item
for (int i = 0; i < outputBuffer.size() - 1; i++) {
System.out.print(outputBuffer.get(i) + "-");
}
// print the last item by itself, no delimiter
System.out.print(outputBuffer.get(outputBuffer.size() - 1));
Here's the output:
E-E-M-M-A-A-N-N
And since the phaser is the only coordination point, it also works great with more than 2 threads. For example, here is the output with 10 threads:
E-E-E-E-E-E-E-E-E-E-M-M-M-M-M-M-M-M-M-M-A-A-A-A-A-A-A-A-A-A-N-N-N-N-N-N-N-N-N-N