简体   繁体   中英

Stop thread anytime i want

I have a method, wich supposed to interrupt a thread, but it's not. Do I need to always check the thread interrupted in the while method to stop the thread? How can I just terminate the thread at anytime?

solverTh = new Thread(new Runnable() {
        @Override
        public void run() {
            while(somethingistrue){
                //do lot of stuff here for long time
            }
        }
    });
    solverTh.start(); 
}

public void terminate(){
    if(solverTh != null){
        solverTh.interrupt();
    }
}

okay than I thought the "lot of stuff" is irrelevant, but I will post it than. It makes openGL operations, I added the boolean variable "terminated" to the code it works now, I just wanted to find a nicer solution: (glc is a GLCanvas, and the rotmultiplecube method rotates 3 objects) Anyways I've solved the problem now, thanks for the answers.

            terminated = false;
            try {
                Thread.sleep(2000);
            } catch (InterruptedException ex) {
                Logger.getLogger(BruteForce.class.getName()).log(Level.SEVERE, null, ex);
            }

            int colorToBeSolved = Statics.RED_BLUE_TABLE[stateToBeSolved];
            System.out.println(stateToBeSolved + "," + colorToBeSolved);
            if(entities[0].getColor() != colorToBeSolved){
                if(terminated) return;
                fullRotate(Statics.FIRST_ROW, Statics.DOWN);
            }
            if(entities[1].getColor() != colorToBeSolved){
                if(terminated) return;
                fullRotate(Statics.SECOND_COL, Statics.RIGHT);
            }
            if(entities[2].getColor() != colorToBeSolved){
                if(terminated) return;
                fullRotate(Statics.THIRD_COL, Statics.RIGHT);
            }
            if(entities[3].getColor() != colorToBeSolved){
                if(terminated) return;
                fullRotate(Statics.SECOND_ROW, Statics.DOWN);
            }
            if(entities[6].getColor() != colorToBeSolved){
                if(terminated) return;
                fullRotate(Statics.THIDR_ROW, Statics.DOWN);
            }

            for(int i = 0; i < 9; ++i){
                int col = i % 3;
                int row = 3 + i/3;
                while(entities[i].getState() != stateToBeSolved){
                    for(int j = 0;j < 2; ++j){
                        if(entities[i].getState() != stateToBeSolved){
                            if(terminated) return;
                            fullRotate(col, Statics.LEFT);
                            if(terminated) return;
                            fullRotate(row, Statics.UP);
                            if(terminated) return;
                            fullRotate(col, Statics.RIGHT);
                            if(terminated) return;
                            fullRotate(row, Statics.DOWN);
                        }
                    }
                    for(int j = 0;j < 2; ++j){
                        if(entities[i].getState() != stateToBeSolved){
                            if(terminated) return;
                            fullRotate(col, Statics.RIGHT);
                            if(terminated) return;
                            fullRotate(row, Statics.UP);
                            if(terminated) return;
                            fullRotate(col, Statics.LEFT);
                            if(terminated) return;
                            fullRotate(row, Statics.DOWN);
                        }
                    }
                }
            }
        }

and the fullrotate method:

private void fullRotate(int selectionIndex, int direction){
    for(int i = 0; i < 9; ++i){
        glc.rotMultipleCubeSlow(selectionIndex, direction);
        try {
            Thread.sleep(20);
        } catch (InterruptedException ex) {
            terminate();
        }
    }
    glc.setMovesText(selectionIndex, direction);        
    glc.setMultipleStateAndColorsByTable(selectionIndex, direction);
    glc.isEntitiesRight();
}
while(somethingistrue !Thread.currentThread().isInterrupted()){
  //do lot of stuff here for long time
}

Does not have to work for blocking IO. Use dirty tricks: override Thread.interrupt() close IO object, cause IOException that if properly handled may end thread run method.

The elegant solution is to modify your fullRotate() method to throw InterruptedException.

private void fullRotate(int selectionIndex, int direction)
       throws InterruptedException{
    for(int i = 0; i < 9; ++i){
        glc.rotMultipleCubeSlow(selectionIndex, direction);
        Thread.yield();
    }
    glc.setMovesText(selectionIndex, direction);        
    glc.setMultipleStateAndColorsByTable(selectionIndex, direction);
    glc.isEntitiesRight();
}
  • When you call Thread.interrupt() you cause InterruptedException when any of the methods that throw it is invoked, in your case the Thread.sleep() or Thread.yield(). This means that the best approach is to use it to actually interrupt the calculation.
  • You still need to check Thread.currentThread().isInterrupted() if you want immediate response to your Thread.interrupt()
  • You can ether remove if(terminated) return; or substitute it with Thread.currentThread().isInterrupted() check. Removing will be fine because the Thread.sleep(20)/Thread.yield() from fullRotate() will throw the InterruptedException. Also code will be cleaner without all these if(terminated) all over the place.
  • Use Thread.yield() instead for Thread.sleep(20). Obviously you don't want to sleep, because you put 20 millis. 20 milis is very close to the context switch time quantum. The thread will ether sleep more, or less. You don't want it to sleep more without any reason, so use yield().

Your thread run() then becomes:

solverTh = new Thread(new Runnable() {
    @Override
    public void run() {
        while(somethingistrue && 
              !Thread.currentThread().isInterrupted()) {
            try {
                //do lot of stuff here for long time
            } catch (InterruptedException ex) {
                // handle stop processing 
            }
        }
    }
});
solverTh.start(); 

Also you have to remove the try catch from the following:

        try {
            Thread.sleep(2000);
        } catch (InterruptedException ex) {
            Logger.getLogger(BruteForce.class.getName()).log(Level.SEVERE, null, ex);
        }

The only way to interrupt thread is to make it exit itself. Strightforward interruption is not even implemented in Java because of deadlocks possibility. So your thread code must look like:

solverTh = new Thread(new Runnable() {
    @Override
    public void run() {
        while(somethingistrue) 
            // Do a little stuff here
        }
    }
});
solverTh.start(); 

And somethingistrue is a kind of a signal for thread to interrupt.

The only thing that can reliably stop the execution of one thread from another is the OS. So, there are not many choices:

1) Signal the thread to stop itself. This scheme kinda depends on what the thread is doing. If it's running on another processor or stuck on a blocking call you cannot unblock, (note-many blocking calls can be persuaded to return early), there can be problems.

What is 'lot of stuff' doing?

2) Use an OS call to terminate the thread. This can be a viable option, depending on what the thread does. If there is any possibility of terminating the thread while it holds a public lock on a vital resource, (eg. it's in the middle of a malloc() and has the memory-manager locked), then you can get into trouble. You have to be sure of what thread is doing to safely abort it in this way.

3) Use a separate process to run the 'stuff'. This will obviously work OK, but usually involves slow and painful inter-process comms to pass data and return results.

4) Design the app so that it does not need to terminate the thread. Some apps never need to terminate any threads except at app shutdown, so there's no problem - the OS can stop anything. In those cases where a thread must be 'stopped' during an app run and is running a lengthy CPU-intensive operation or is blocked for a long and possibly indeterminate period, 'orphaning' a thread by setting its priority to minimum/idle and just leaving it to eventually die off is another common approach.

The worst possible scenario is a thread running a lot of stuff for long time that uses the memory-manager or other public locks, possibly in a library where you don't know exactly what it's doing, can't be hooked and reads/writes data in such a way that 'orphaning' it off means that another thread cannot be started to use the data. You're really stuft then and you may have to terminate the app and restart. It's just best to avoid designs where a thread can get into such a state:)

5) Forgot one - if the thread is using data you can get at, setting something to NULL, 0, MaxInt or some other like bodge can cause an exception to be raised in the thread running the long stuff. When execution bubbles out of long stuff, the thread can check the Interrupted state in the exception handler and exit if set.

When a thread is running ( consuming CPU cycles ), then it will not by default ( automatically ) respond to Thread.interrupt() . You will have to write the code to do this explicitly.

Break up //do lot of stuff here for long time into 2 or more steps, and insert between these steps checks for the Thread.currentThread().isInterrupted() - if true - break out, else continue. This is only safe way to achieve what you want.

It depends on what the long running stuff is, you will have to design the steps and decide when its best to check for interruption and breakout.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM