16

I'm trying to stop a thread but I can't do that :

public class Middleware {

public void read() {
    try {
        socket = new Socket("192.168.1.8", 2001);

        // code .. 

        Scan scan = new Scan();
        thread = new Thread(scan);
        thread.start();

    } catch (UnknownHostException ex) {
        ex.printStackTrace();

    } catch (IOException ex) {
        ex.printStackTrace();
    }
}

class Scan extends Thread {

    public void run() {

        while (true) {
            try {
            // my code goes here

            } catch (IOException ex) {
                thread.currentThread().interrupt();
            }
        }
    }
}

public void stop() {
    Thread.currentThread().interrupt();
}

// get and setters
}

So, even when i call the method 'stop' the thread don't stop. It keeps alive.

How can I interrupt/stop this thread ?

UPDATE (@little approach)

private void tb_startActionPerformed(java.awt.event.ActionEvent evt) {                                         
    Middleware middleware = new Middleware();

    if (tb_start.getText().equals("Start")){
        tb_start.setText("Stop");

        // starting to read rfid tags
        middleware.read();
    }else{
        tb_start.setText("Start");

        // stop reading rfid tags
        middleware.stop();
    }
}

The Middleware class :

public class Middleware {

    private Scan scan;

    public void read() {

        scan = new Scan();
        scan.start();
    }

    private class Scan extends Thread {

        @Override
        public void run() {
            while (!Thread.currentThread().isInterrupted()) {
                System.out.println("reading...");
            }
        }
    }

    public void stop() {
        if (scan != null) {
            scan.interrupt();
        }
    }
}

But when I try to stop the thread, it doesn't.

What could be wrong in the code above ?

jww
  • 97,681
  • 90
  • 411
  • 885
Valter Silva
  • 16,446
  • 52
  • 137
  • 218
  • possible duplicate of [Stopping a Thread in Java?](http://stackoverflow.com/questions/247455/stopping-a-thread-in-java) – KevinDTimm Jul 06 '11 at 15:49

8 Answers8

21

There's really no reason you need to use a volatile flag. Instead, just query the thread for its state with isInterrupted(). Also, why are you wrapping your Scan thread object in another thread object? That seems completely unnecessary to me.

Here' what you should be doing

public class Middleware {
    private Scan scan;

    public void read() {
        try {
            // do stuff

            scan = new Scan();
            scan.start();
        } catch (UnknownHostException ex) {
            // handle exception
        } catch (IOException ex) {
            // handle exception
        }
    }

    private class Scan extends Thread {

        @Override
        public void run() {
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    // my code goes here
                } catch (IOException ex) {
                    Thread.currentThread().interrupt();
                }
            }
        }
    }

    public void stop() {
        if(scan != null){
            scan.interrupt();
        }
    }
}

Here's an example. Also, I wouldn't recommend extending Thread.

Community
  • 1
  • 1
mre
  • 43,520
  • 33
  • 120
  • 170
  • What about the possible SecurityException of interrupt? `Unless the current thread is interrupting itself, which is always permitted, the checkAccess method of this thread is invoked, which may cause a SecurityException to be thrown.` – Leonard Brünings Jul 07 '11 at 15:09
  • After Thread was interrupted by interrupt() how can one start it again , meaning resume it. – Volodymyr Levytskyi Aug 31 '13 at 15:04
  • "There's really no reason you need to use a volatile flag." Actually that's not really true. The circumstances under which the interrupt flag is cleared are pretty confusing, and if the code in the thread calls any 3rd party libraries, there's a good chance calling `theThread.interrupt()` won't actually work. – Peter Oct 07 '15 at 03:09
  • @BobbyBrown I answered this a while ago, but IIRC it has something to do with preferring composition over inheritance. But as a quick and dirty solution, it's fine. – mre Jan 17 '17 at 12:01
11

Simply return; from your while and the thread will die, no need to call stop() or interrupt(). If you want to do it externally then use this pattern and call requestStop().

class Scan extends Thread {
    private volatile stop = false;
    public void run() {

        while (!stop) {
            try {
            // my code goes here

            } catch (IOException ex) {
                stop = true;
            }
        }
    }

    public void requestStop() {
        stop = true;
    }

}
Leonard Brünings
  • 12,408
  • 1
  • 46
  • 66
5

"Many uses of stop() should be replaced by code that simply modifies some variable to indicate that the target thread should stop running."—java.lang.Thread

trashgod
  • 203,806
  • 29
  • 246
  • 1,045
5

The usual way to stop a thread is to have a volatile flag and then check that in the run method. i.e.

class Scan extends Thread {
    volatile stop = false;
    public void run() {

        while (!stop) {
            try {
            // my code goes here

            } catch (IOException ex) {
                thread.currentThread().interrupt();
            }
        }
    }

    public void stop(){
        stop = true;
    }
}

You can then call scan.stop().

Jim
  • 22,354
  • 6
  • 52
  • 80
  • 1
    in your case you would need to set stop to true in the catch instead of calling interrupt – Leonard Brünings Jul 06 '11 at 15:49
  • volative stop can be an attribute ? so i can call a method 'stop' to change the value from it ? – Valter Silva Jul 06 '11 at 15:51
  • If there was a blocking code in the try, like waiting for connection to be accepted or scanner.nextLine() that waits for input from keyboard, will this code still work? – Mohammad Jafar Mashhadi Jun 27 '13 at 18:02
  • Why `volatile`, why not just a regular, private variable? – raffian Aug 31 '13 at 02:32
  • @raffian Threads have a local copy of variables which may not have the latest value of a variable. Volatile will ensure that`stop` will not use a cached value. – Jim Sep 02 '13 at 08:05
  • This is not working. Telling me to remove the try/catch clause. – basickarl Oct 25 '13 at 18:00
  • @KarlMorrison The try catch is from the original askers code. It's not needed and can be removed if your code doesn't throw an `IOException`. – Jim Oct 26 '13 at 18:30
5

if you want to interrupt a running thread, then you need to have access to the thread object.

thread = new Thread(scan);
thread.start();

then say

thread.interrupt();

this will interrupt the running thread.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
Anantha Sharma
  • 9,920
  • 4
  • 33
  • 35
1

Completely agree with Jim.. Just to add If your thread is blocked inside the try block for instance reading on a datastream etc then interrupt the thread as well or close the stream. In both cases the thread should be wakened up again and it will then be able to see the change in the value of "stop" boolean and die naturally by falling out of the run method. At least this is what I did to kill my threads in the shutdown thread for my server.

Osama Javed
  • 1,432
  • 1
  • 16
  • 21
0
    public void run()
    { 
         while (!Thread.currentThread().isInterrupted()) 
         {
        //do something here
        if(condition)
       {
           Thread.currentThread().interrupt();
       }
   }
Sylver
  • 11
  • 2
  • 2
    Could you please specify a bit more about your answer? It's usually good form to add some sort of explanation. – Bono Mar 04 '15 at 11:20
0

Rather than using Thread.stop() or Thread.interrupt() you can go for the external locks. Basically, when you try to utilize an intrinsic lock most of the time any interrupt you perform on the thread is uncontrollable.

A re-entrant lock provides you the methods as mentioned below

lock() 
unlock() 
tryLock() 
lockInterruptibly() 
isHeldByCurrentThread() 
getHoldCount() 

Check the below example

final ReentrantLock reentrantLock = new ReentrantLock();    
    @Override
    public void performTask() {
        reentrantLock.lock();
        try { 
             System.out.println(Thread.currentThread().getName() + ": Lock acquired.");
             System.out.println("Processing...");
             Thread.sleep(2000);
        } catch (InterruptedException e) {
             e.printStackTrace();
        } finally {
             System.out.println(Thread.currentThread().getName() + ": Lock released.");
         reentrantLock.unlock();
            }
    }

This makes your code elegant and handle the interrupt in a better way.

wandermonk
  • 6,856
  • 6
  • 43
  • 93