Search code examples
javamultithreadinginterruptterminate

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();
}

Solution

  • 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);
            }