-1

My Java code creates a thread on button click. Every time if the button is clicked a thread is created. I want to kill the previous thread if button is clicked again. how can I do this? below is the portion of code inside buttonclicklistener

myThread= new Thread() 
                {
                    public void run() {
                        diff2 = Math.abs(d3.getTime() - d1.getTime());
                        long diffseconds = diff2 /1000;
                        final long start = System.currentTimeMillis()/1000;
                        tv_timecount=(TextView)findViewById(R.id.tv_timeCount);
                        while(diffseconds>0)
                        {
                            tv_timecount.setText(String.valueOf(diffseconds--));
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            if(myThread.isInterrupted())
                                break;

                        }
                    }
                };
                myThread.start();

I want to stop this Thread.

  • 1
    This code may run into issues when calling `setText()` from a thread. See https://stackoverflow.com/questions/6049882/how-to-textview-settext-from-thread for details. – PatS Nov 21 '19 at 17:59
  • its not creating any issue...i am updating the UI in this thread. – Azhar Abbasi Nov 21 '19 at 18:16
  • If the code works properly when updating the UI from a Thread then that's good. I haven't done much Android development to know for sure if updating the UI in threads is safe. I found this (but it is dated, approx 9 years ago) so maybe this is no longer an issue. https://stackoverflow.com/questions/4369537/update-ui-from-thread – PatS Nov 21 '19 at 20:27
  • 2
    Yeah, don't update the UI from a separate thread. If it's not throwing an Exception here, then you're just lucky. It will eventually bite you. – Mike M. Nov 22 '19 at 00:10

3 Answers3

2

Many ways,

1: Using deprecated stop

Thread t = new Thread();
t.start();
t.stop(); //this is deprecated but it stops the thread

2: Using interrupt

Thread t = new Thread();
t.start();
t.interrupt();

3: Killing a thread with a while loop

boolean running = true;
Thread t = new Thread(() -> { 
    while (running) {
       System.out.println("Running");

       try { Thread.sleep(100); } catch (Throwable t) {}
    }
});
t.start();
running = false;
Joe
  • 1,316
  • 9
  • 17
  • 3
    @AzharAbbasi You have a `Thread#sleep(long)` call which will throw an `InterruptedException` if the `Thread` is interrupted. Use a `break` statement to break out of the loop when you catch that exception. Also, see [`Thread#currentThread()`](https://docs.oracle.com/en/java/javase/13/docs/api/java.base/java/lang/Thread.html#currentThread()), [`Thread#interrupted()`](https://docs.oracle.com/en/java/javase/13/docs/api/java.base/java/lang/Thread.html#interrupted()), and [`Thread#isInterrupted()`](https://docs.oracle.com/en/java/javase/13/docs/api/java.base/java/lang/Thread.html#isInterrupted()). – Slaw Nov 21 '19 at 17:49
  • 2
    @AzarAbbasi, You didn't say which of the three answers you tried. The answers provided are technically sound. If they are not working, there is likely some other bug/problem in your code. The most likely issue is that the operation being run in the thread is blocking and preventing the thread from stopping/exiting. – PatS Nov 21 '19 at 17:52
  • 1
    @Joe, `boolean running` is not `volatile`, so the code can never stop. Add the word `volatile` to prevent that optimization – Michel_T. Nov 21 '19 at 18:00
  • Thats true, but it works under most scenarios, ive never really had a problem without using volatile – Joe Nov 21 '19 at 18:01
  • 1
    It just a coincidence or not enough of optimation that it works on your platform. It can broke any moment. – Michel_T. Nov 21 '19 at 18:05
  • 1
    @Michel is correct and unfortunately anecdotal evidence is not useful in this case. The way the `running` field is being used requires it to be `volatile` to ensure proper behavior. This has to do with the Java memory model. If not `volatile` then no _happens-before_ relationship is created which means the code is broken from a concurrency point-of-view. – Slaw Nov 21 '19 at 18:18
  • I tried all three they didn't work. Prolem is solved by handling interrupted Exception. if i use flag then it breaks the loop. but i wanted to keep current thread running and stop the thread created on previous click. thanks you all – Azhar Abbasi Nov 21 '19 at 18:30
1

You didn't mention why exactly you can't stop the thread, so I've some assumes which problems you might have.

1.Main reason why interrupt doesn't work in your code is because you catch InterruptedException and do noghing about that. But you should set interrupted flag by yourself after that, using Thread.currentThread().interrupt()

2.You can click the button 2 or more times at the same time, so all the clicks will try to stop the same thread, but every of them then start their own thread, so all but one of these thread (or pointer to them) will leak from you. This can be solved using synchronized function. The general code, which handles button click should be looking like the code below:

private Thread myThread;
private synchronized void buttonClick() throws InterruptedException //NOTE synchronized
{
    if (myThread != null) {
        myThread.interrupt();
        myThread.join();
    }

    myThread = new Thread(() -> {
        diff2 = Math.abs(d3.getTime() - d1.getTime());
        long diffseconds = diff2 / 1000;
        final long start = System.currentTimeMillis() / 1000;
        tv_timecount = (TextView) findViewById(R.id.tv_timeCount);
        while (diffseconds > 0) {
            tv_timecount.setText(String.valueOf(diffseconds--));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt(); // NOTE: flag interrupt gets set
            }
            if (myThread.isInterrupted())
                break;
        }
    });
}
Michel_T.
  • 2,741
  • 5
  • 21
  • 31
0

Best way would be to use a flag. Introduce a flag inside your while method Add logic to check if flag is set and only then execute the code in your while loop.

while(diffseconds>0)
{
    synchronized(Object.class){
    if(flag == set) break;
    }
 //your code
}

You can reset/set flag on button click from other threads or the main execution.

Dilip G
  • 61
  • 2
  • 1
    I see you are new to SO (reputation of 11) so I wanted to welcome you! Congrats on contributing an answer. Many people find this hard to do. Keep contributing, and when answering try to explain why your solution works. Best regards. – PatS Nov 21 '19 at 17:56
  • yes i am new on stackoverflow and will be needing help of people like you. thanks – Azhar Abbasi Nov 21 '19 at 19:10