Java - terminating a method in a thread

I have a Java thread with a run method that computes a lot of things. You can think of it as a series of mathematical statements as follows. Please note that in each calculation other methods may be used, which, in turn, may have additional cycles, etc.

 public void run() { [computation 1 goes here here that takes a few seconds] [computation 2 goes here that takes a few seconds] .... [computation 30 goes here that takes a few seconds] } 

There is a GUI that outputs the output of these statements as they are output, and I would like the user to say β€œStop” whenever he wants. Here are two methods that I thought about


Method 1: Lots of Boolean Checks [LOOKS TERRIBLE]

 private boolean stop; public void run() { if(!stop) [computation 1 goes here here that takes a few seconds] if(!stop) [computation 2 goes here that takes a few seconds] .... if(!stop) [computation 30 goes here that takes a few seconds] } 

In this method, when the stop flag is set to true, the calculations are completed. Notice how stupid it is with 30 if statements. It is important to note that the critical question is how often to establish these conditions. Note that the calculations on each line are not necessarily one line. Taken to the extreme, does EVERY line in the run() method deserve to be called if(!stop) above it? It doesn't look like a good design.

Method 2: Generalize Computing [CANNOT DO IT]

 pirivate boolean stop; public void run() { for(int i = 0; i < computationsN && !stop; i++) { computuations.get(i).compute(); } 

I assume that this method will be proposed, so I would just like to say that this is not possible in my case, given the explicit change in the lines, which I call "calculations" for simplicity. I usually did this for threads, which are the base while loops, and it works great for such purposes. But not in this case, when the run() method is just a huge variable code method.


Any other solutions? It seems like this should be a universal problem. Thanks in advance!

+7
java multithreading
source share
3 answers

what you want to do can be done using method 2, but you must use the strategy template , this is really one more thing you need, because it allows you to simplify your calculations in one line, as you actually did in method 2 .

It works as follows: it allows you to modify the next executable algorithm by performing polymorphism.

enter image description here

So, first you have to make all your algorithms in different classes, and each of them must implement one interface (it can be called Computable ) with one method, i.e. your compute() method.

Ref.

 public interface Computable { public void compute(); } 

And your algorithm classes could be something like this:

  public class AlgorithmX implements Computable { @Override public void compute() { // TODO Your Real Computation here for the Algorithm X } } 

Then in your for chain, your computations collection (or array) is populated with objects that implement Computable , i.e. with your algorithm objects.

 for(int i = 0; i < computations && !stop; i++) { computuations.get(i).compute(); } 

So, you are on the right track with method 2, I hope that now your path will become clearer.

Hooray!

+5
source share

Instead of using the stop flag, you can call interrupt() on the thread to stop it, and inside your run method check to see if (Thread.interrupted()) - true ( interrupt() does not immediately stop the thread , you still need to check Thread.interrupted() ). Thus, you avoid traps, for example, you forget to declare your flag as volatile .

http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Thread.html#interrupt%28%29

With the exception of encapsulating all of your calculations in Runnables , then putting them into an array and iterating over them, which you excluded, method 1 is your best bet. As for how often you should check if your thread is interrupted, it depends on how long it takes to perform your calculations and how quickly you want your program to be in the Stop command, you can add several println(System.currentTimeMillis) statements println(System.currentTimeMillis) to get the idea of ​​computing time, then add if(Thread.interrupted()) return; every 500 milliseconds or so to stop the run method.

I would not immediately exclude method 2, since your calculations should not have anything in common so that you can put them in Runnables

 private ArrayList<Runnable> runnables = new ArrayList<>(); runnables.add(new Runnable() { public void run() { // computation 1 } }) runnables.add(new Runnable() { public void run() { // computation 2 } }) // etc public void run() { for(Runnable runnable: runnables) { if(Thread.interrupted()) return; runnable.run(); } } 
+1
source share

Depending on how your GUI is structured, is there a chance that you could throw an exception (possibly a thrown exception) from the GUI code that would blow a lengthy process?

The key is to look somewhere in your code stream where all the bottleneck is at the point where the check can be inserted. This may not be very obvious (for example, you could hook the redraw manager in the swing application) - and this is certainly not a good practice in the general case, but for a very specific use case this may be appropriate.

If this is not possible, a slightly less detailed approach will be to use this method:

 assertContinue() throws InterruptedException; 

(or perhaps name it ac () to save the input).

you are still spinning in your algorithm, but at least it is less typing.

Oh - and what are these calculations? Do they block I / O locks or locks? If so, then calling Thread.interrupt () will work ...

0
source share

All Articles