I'm learning multithreading in Java, so now I'm creating the classic Tortoise and Hare race application.
For those not familiar with this problem, basically, there's two racers:
The first to reach 1000 meters is the winner.
My code looks like this now:
Main class:
public class THRace {
static Thread hare = new Thread(new ThreadRunner("Hare", 90, 100));
static Thread tortoise = new Thread(new ThreadRunner("Tortoise", 0, 10));
public static void main(String[] args) {
hare.start();
tortoise.start();
}
public static void finished(Thread winner){
if (winner.getName().equals("Hare")) tortoise.interrupt();
else if (winner.getName().equals("Tortoise")) hare.interrupt();
}
}
ThreadRunner class:
import java.util.Random;
public class ThreadRunner implements Runnable {
private String name;
private int rest, speed;
public String getRacerName() {
return name;
}
public ThreadRunner(String name, int rest, int speed) {
this.name = name;
this.rest = rest;
this.speed = speed;
}
@Override
public void run() {
int meters = 0;
Random rn = new Random();
Thread ct = Thread.currentThread();
ct.setName(name);
while(!ct.isInterrupted()){
if(rn.nextInt(100) + 1 > rest){
meters += speed;
System.out.println(this.name + ": " + meters);
}
try {
Thread.sleep(100);
}catch (InterruptedException ex){
return;
//break;
}
if(meters >= 1000){
System.out.println(this.name + ": I finished!");
THRace.finished(ct);
return;
}
}
}
}
When a thread reaches 1000 meters it calls the finished method from the main class and it stops the other thread. My code works just fine, but the problem is what happens when there's a tie (when the hare and the tortoise reach 1000 meters at the same tie), both runners are declared a winner and I don't want this to happen.
For example, you can set the runners to have a 0% rest chance and the same speed, so they both will reach 1000 meters at the same time:
static Thread hare = new Thread(new ThreadRunner("Hare", 0, 10));
static Thread tortoise = new Thread(new ThreadRunner("Tortoise", 0, 10));
And the output will be:
(...)
Tortoise: 950
Hare: 950
Hare: 960
Tortoise: 960
Tortoise: 970
Hare: 970
Tortoise: 980
Hare: 980
Tortoise: 990
Hare: 990
Tortoise: 1000
Hare: 1000
Hare: I finished!
Tortoise: I finished!
Is there a way for me to "lock" the finished method, so only one thread is declared the winner?
If you use the synchronized identifier in front of the finished method, the first thread to call it will lock it until it is finished. Since you are interrupting the other thread, this should work just fine for you.
synchronized public static void finished(Thread winner){
if(winner.isInterrupted()) {
// sorry, the other thread beat you here
return;
}
if (winner.getName().equals("Hare")) tortoise.interrupt();
else if (winner.getName().equals("Tortoise")) hare.interrupt();
}
As mentioned in your comment, if the other thread is already queued up and waiting to get into the finished method, you would need to add a check to see if your were interrupted before declaring yourself the winner.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With