Reputation: 1655
So I'm wrapping my head around multithreading and I made a very basic program to play around with. The idea is simply I would start a couple of threads, and each would race down (decrement) to zero at which point one would be declared the winner and the others would stop immediately. I have used a boolean flag, which terminates the other threads but sometimes they carry on for a bit (I guess until they do the check in the while loop to see if run is still true).
I have tried interrupts but my understanding is that these only work on threads that are sleeping, awaiting etc, and the threads I am using a pretty much running the whole time. I have used system.exit(1) but this doesn't stop them either, at least not immediately. Just wondering what more experienced people would do? Basically I just want a thread to say "OK everybody stop what you are doing RIGHT NOW".
Here is the code:
Runnable Class
public class ThreadRunnable implements Runnable {
private static boolean run;
private int tick;
public ThreadRunnable() {
run = true;
tick = 5;
}
public void run() {
Thread t = Thread.currentThread();
while (run) {
tickDeduction();
if (tick == 0) {
System.out.println("Thread " + (Thread.currentThread().getId()) + " WINS");
this.run = false;
return;
}
}
}
public synchronized void tickDeduction() {
System.out.println("Thread " + (Thread.currentThread().getId()) + " is at tick " + this.tick);
this.tick--;
}
}
Main Class
public static void main(String[] args) {
ThreadRunnable runnableBlue = new ThreadRunnable();
ThreadRunnable runnableRed = new ThreadRunnable();
Thread teamBlue = new Thread(runnableBlue);
Thread teamRed = new Thread(runnableRed);
teamBlue.start();
teamRed.start();
}
Upvotes: 2
Views: 375
Reputation: 719279
Basically I just want a thread to say "OK everybody stop what you are doing RIGHT NOW".
There is no way for a Java application to do that to itself. A debugger might be able to do it though. (Certainly, the JDWP protocol has a command to freeze all threads in the target JVM ...)
The closest you could get within a Java application would be to traverse the tree of ThreadGroups and Threads and apply the deprecated Thread.suspend()
method to each Thread. (Take care to not pause the current thread ...) But the suspend method is dangerous (see the javadocs), and there is no guarantee that you will see all threads in the traversal. And of course, this (hypothetical) procedure is not instantaneous.
Upvotes: 2
Reputation: 29436
Use a flag that can be claimed only once, and only first time. One such thing is an AtomicBoolean
with a compareAndSet()
method. To stop other threads you can send an interrupt()
.
(Java used to have powers to stop and kill threads, but that leads to issues. Interrupts are the only reliable methods to throw a thread off its normal execution.)
import java.util.Random;
import java.util.concurrent.atomic.AtomicBoolean;
public class Main {
public static void main(String[] args) {
final AtomicBoolean flag = new AtomicBoolean(false);
final Thread[] runners = new Thread[5];
final Random random = new Random();
for (int i = 0 ; i < runners.length; i++){
runners[i] = new Thread("Runner # " + i){
@Override
public void run() {
try {
// wait for random time
Thread.sleep(1000 + random.nextInt(1000));
// try to claim the flag
boolean claimed = flag.compareAndSet(false,true);
if(claimed){
System.out.println(this.getName() + " has won the race.");
// interrupt others
for (Thread t : runners){
if(!t.equals(this)){
t.interrupt();
}
}
}else {
System.out.println(this.getName() + " has very closely lost the race.");
}
} catch (InterruptedException e) {
System.out.println(this.getName() + " has lost the race.");
}
}
};
}
// get set go
for (int i = 0 ; i < runners.length; i++){
runners[i].start();
}
}
}
Upvotes: 1