In my Android app, I have a class that extends Thread that runs when there's an established internet connection (3G/WIFI).
When the app is loaded, if an internet connection is established, I instantiate the class like this:
MyThread thread = new MyThread(); // (it calls its own start() method)
In the thread, if the connection is lost, I want to destroy the Thread. I was told not to run finalize(), how would I destroy it so that thread == null is true?
Edit: The reason I was asking was, later on, I would like to restart the thread in case connectivity returned, and a check to see if (thread == null) would have been easy. I could just use a flag to indicate the thread needs to be restarted or check to see if it was interrupted. Thanks for the helpful comments so far.
Generally, you don't subclass Thread. You create a Runnable, and pass it into a Thread object, or better yet, an ExecutorService.
But you don't have to worry about cleaning up after the thread is done, it will be handled automatically by the garbage collector. If you want your own local reference to be null, just null it out yourself, or better yet, don't hang on to it.
new Thread( new Runnable() {
public void run() {
// put your stuff here
}
} ).start();
Try this,
A thread of execution will live until it has finished executing its run() method, then
it either moves to the dead state or in the thread pool.
Its always better to control the run() method using aboolean variable.
eg:
boolean isRunning = true;
new Thread(new Runnable()
{
public void run()
{
while(isRunning)
{
// Keep doing your work here....
if (!isRunning){
break;
}
}
}
}).start();
Related
I am a total beginner to android and Java development, and I am currently trying to make a metronome.
The first problem I encountered after getting the sound playback to work, is that whenever the metronome played the app would stop responding - that's when I learned about threads and how I should use a new thread for my audio playback.
Creating a new thread helped and now the app runs fine, but I can't get the thread to stop/interrupt. I've read maybe 50 articles already about threads and interrupts and I can't figure it out.
Here is my 'Player' class code, which I've mostly copied from another Stack Overflow post (I have tried countless other ways and variations and none worked):
package com.example.t.firstapp;
import android.util.Log;
public class Player implements Runnable {
Thread backgroundThread;
Metronome m;
public void start() {
if (backgroundThread == null) {
backgroundThread = new Thread(this);
m = new Metronome();
backgroundThread.start();
}
}
public void stop() {
if (backgroundThread != null) {
backgroundThread.interrupt();
}
}
public void run() {
try {
Log.i("a", "Thread starting.");
while (!backgroundThread.isInterrupted()) {
m.play();
}
Log.i("b", "Thread stopping.");
throw new InterruptedException(); // ???
} catch (InterruptedException ex) {
// important you respond to the InterruptedException and stop processing
// when its thrown! Notice this is outside the while loop.
Log.i("c", "Thread shutting down as it was requested to stop.");
} finally {
backgroundThread = null;
}
}
}
Note the line marked with "???". I added that one myself because otherwise the "catch (InterruptedException ex)" returned an error.
Here is the relevant code from my MainActivity class:
public class MainActivity extends AppCompatActivity {
...
public Player p;
...
public void play() {
p = new Player();
p.start();
}
public void stop() {
p.stop();
}
}
Calling p.stop(); from within the method 'stop' doesn't actually do anything. This is where I get stuck. If I call p.stop() immediately after I start the thread, like this:
public void play() {
p = new Player();
p.start();
p.stop();
}
Then it works, and I see all of the relevant log messages from the Player class. Why doesn't p.stop() work when I call it from my 'stop' method? Is it because I am calling it from a different method, or is it because I am not calling it immediately?
Any help would be greatly appreciated since this is extremely frustrating. I have been studying and practicing Android development for only a week now, but I haven't done anything over the last 5 days but try to solve this problem. Thanks
You misunderstood the concept of interruption. Interupting is not some magical way of forcing the thread to stop, rather it will only work for methods that have interruption support - like sleeping.
Take a look at the Thread#interrupt() API, where it lists interrupt supported methods:
If this thread is blocked in an invocation of the wait(), wait(long), or wait(long, int) methods of the Object class, or of the join(), join(long), join(long, int), sleep(long), or sleep(long, int), methods of this class, then its interrupt status will be cleared and it will receive an InterruptedException.
If this thread is blocked in an I/O operation upon an interruptible channel then the channel will be closed, the thread's interrupt status will be set, and the thread will receive a ClosedByInterruptException.
If this thread is blocked in a Selector then the thread's interrupt status will be set and it will return immediately from the selection operation, possibly with a non-zero value, just as if the selector's wakeup method were invoked.
If none of the previous conditions hold then this thread's interrupt status will be set.
You can nicely implement your own methods with interrupt support, by contantly checking for the interrupt status.
Now let's see how we can solve your problem.
According to your comment, m.play() does not return, meaning, once m.play() is called, the while never checks if the thread has been interrupted; in turn it will never stop, since m.play() isn't implemented to support interrupts. This should also explain why the compiler complains that nobody throws an InterruptedException. (The reason it worked if interrupted immediately, is that the interrupt status is changed before it reaches the while... Think of it.)
Now, I assume that, if you will call m.stop(), m.play() will return, successfully rechecking for thread interruption. That's why it worked, as mentioned in comment.
But look, there's no real use of interrupting the thread - since all you have to do is call m.stop() and release the m.play(), just play and wait to return - which means stop has been called. Same to the while loop, drop it all the way.
public void run() {
Log.i("a", "Thread starting.");
m.play(); // blocks till stopped from some other thread...
Log.i("b", "Thread stopping.");
Log.i("c", "Thread shutting down as it was requested to stop.");
backgroundThread = null;
}
One case where I may see a use of the while and interrupt, if m.play() may return earlier than by calling m.stop() (say, by some exception), and you want to restart the metronome until stop is called; then a loop may be on the rescue, and interrupt may signal that it was actually stopped by calling m.stop().
public void run() {
Log.i("a", "Thread starting.");
while (!backgroundThread.isInterrupted()) {
m.play();
if(!backgroundThread.isInterrupted())
Log.i("b", "Stopped by exception, restarting....");
}
Log.i("c", "Thread stopping.");
Log.i("d", "Thread shutting down as it was requested to stop.");
backgroundThread = null;
}
i have an Android App published in the Play Store, and the crashreports show a Fatal Exception: java.lang.IllegalThreadStateException: Thread already started
in
public void refresh(){
if (Thread.currentThread() != mThread) {
mThread = new Thread() {
#Override
public void run() {
refresh();
}
};
mThread.start();//<<<<<<<<<<<<<here
return;
}
doSomeCoolStuff();
}
how can this happen? it is a new thread?
Metin Kale
This can happen in case of a race condition. Between the two statements (assigning a value to mThread and calling the start() method), the execution can switch to another thread, which can enter the refresh() method again, assign a different thread to mThread, and then start it. When the first thread resumes execution, mThread will contain a different thread (which has already been started), and the start() method will fail with the exception that you describe.
One way to fix this is to store the result of new Thread() in a local variable, then call the start() method on that variable, and then save it into the field. (This may not be the most appropriate fix, but it's not possible to say more without knowing more details about the context where the problem happens.)
Probably your mThread is already started and running, thats why do you get that exception.
Try to check the state of mThread, and start it only when is in Thread.State.NEW state.
if (mThread.getState() == Thread.State.NEW)
{
mThread.start();
}
Thread.State.NEW: The thread has been created, but has never been started.
I'm trying to terminate a thread but it doesn't interrupt or stop. All of this are part of controller of a software called Webots. I use this to simulate a multi robot system. In the controller of each robot, I start a thread which receive messages through robots receivers. This thread must start at first, and terminate when simulation ends.
The run method for this thread look like this:
public void run() {
while (true)
{
String M = recieveMessage();
char[] chars = M.toCharArray();
if(chars[0]==robotName||chars[0]=='0')
messages.add(M);
}
}
In the main controller I have code that look like this:
MessageThread MT = new MessageThread(messages, receiver,getName());
MT.start();
for (int i = 0; i < 100; i++)
{
try
{
Thread.sleep(25); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println(messages.get(messages.size()-1));
}
MT.interrupt();//MT = null;
System.out.println(MT.interrupted());
It's not important what I do in my main controller, so don't judge it. For example, messages is an ArrayList. It's like a buffer which MT put messages in and the main thread reads from. I use it because the receiver and emitter are not synchronized.
If I call interrupt() or MT = null but interrupted() it returns false and MT continues to run. Is there anything wrong in my code?
I read some topics like:
http://docs.oracle.com/javase/1.5.0/docs/guide/misc/threadPrimitiveDeprecation.html
How do you kill a Thread in Java?
interrupt() doesn't work
Java: How interrupt/stop a thread?
and so on but I couldn't find any useful answer.
Edit
Thanks everyone, I've made changes to my code. I added this to the MessageThread class:
private volatile boolean isRunning = true;
Then I used while(isRunning) instead of while(true) and I added
public void kill()
{
isRunning = false;
}
and called MT.kill() instead of MT.interrupt().
It worked but I couldn't find out what's wrong with interrupt(). I read the link which #ExtremeCoders recommended. However, I'm still confused. It says "a thread must support its own interruption". So do I have to overwrite the interrupt() method? I can't call interrupt to terminate a thread?
Thanks again.
Interrupting a thread just sets a flag on the thread. If the thread never checks the flag, it won't respond. By creating your own boolean member, you've duplicated that functionality unnecessarily.
Here's the general pattern for what you are trying to do:
#Override
public void run() {
while(!Thread.interrupted() {
/* Do something. */
}
Thread.currentThread().interrupt();
}
This will allow you to call MT.interrupt() as you expected. It's better than creating your own flag and custom method to set it: you can use your Runnable task with high-level tools like ExecutorService and cancellation will work because you used the standard API; same is true for interruption of an entire ThreadGroup.
Calling Thread.interrupted() clears the interruption status of a thread; we set it by calling Thread.currentThread().interrupt(), the status is set again so that callers of run() can detect the interrupted state. This might not always be desirable however.
I'm starting a thread which loops indefinitely until a certain event occurs. The problem is, I want to start this thread, and then return to the normal execution of my program. However, after starting the thread, the code seems to get stuck.
Code:
public void init()
{
Runnable thread = new Runnable()
{
public void run()
{
while(something)
{
//do something
}
}
};
System.out.println("Starting thread..");
new Thread(thread).run();
System.out.println("Returning");
return;
}
When I start this, I get the output "Starting thread" but I don't get "returning" until the conditions for the while loop in the run() stop being true.
Any ideas how I can make it work asynchronously?
Use start rather than run to start a Thread. The latter just invokes the run method synchronously
new Thread(thread).start();
Read: Defining and Starting a Thread
You may try this in your code:-
new Thread(thread).start();
like:-
public void init()
{
Runnable thread = new Runnable()
{
public void run()
{
while(something)
{
//do something
}
}
};
System.out.println("Starting thread..");
new Thread(thread).start(); //use start() instead of run()
System.out.println("Returning");
return;
}
You want to call new Thread(thread).start() instead of run().
Are you sure about your approach? You say:
The thread should loop indefinitely until certain event occurs.
that's an enormous loss of computational resource, the program is principally bound to get slow & fail. You may want to put the thread in wait() mode and catch InterruptedException to wake it up upon occurrence of your event of interest. If this preliminary understanding of what you are trying to accomplish is true then Id' strongly suggest you to revise your approach. Computing resource is expensive, don't waste it in relentless looping.
I'm looking for a clean design/solution for this problem: I have two threads, that may run as long as the user wants to, but eventually stop when the user issues the stop command. However if one of the threads ends abruptly (eg. because of a runtime exception) I want to stop the other thread.
Now both threads execute a Runnable (so when I say 'stop a thread' what I mean is that I call a stop() method on the Runnable instance), what I'm thinking is to avoid using threads (Thread class) and use the CompletionService interface and then submit both Runnables to an instance of this service.
With this I would use the CompletionService's method take(), when this method returns I would stop both Runnables since I know that at least one of them already finished. Now, this works, but if possible I would like to know of a simpler/better solution for my case.
Also, what is a good solution when we have n threads and as soon as one of them finishes to stop execution of all the others ?
Thanks in advance.
There is no Runnable.stop() method, so that is an obvious non-starter.
Don't use Thread.stop()! It is fundamentally unsafe in the vast majority of cases.
Here are a couple of approaches that should work, if implemented correctly.
You could have both threads regularly check some common flag variable (e.g. call it stopNow), and arrange that both threads set it when they finish. (The flag variable needs to be volatile ... or properly synchronized.)
You could have both threads regularly call the Thread.isInterrupted() method to see if it has been interrupted. Then each thread needs to call Thread.interrupt() on the other one when it finishes.
I know Runnable doesn't have that method, but my implementation of Runnable that I pass to the threads does have it, and when calling it the runner will finish the run() method (something like Corsika's code, below this answer).
From what I can tell, Corsika's code assumes that there is a stop() method that will do the right thing when called. The real question is how have you do implemented it? Or how do you intend to implement it?
If you already have an implementation that works, then you've got a solution to the problem.
Otherwise, my answer gives two possible approaches to implementing the "stop now" functionality.
I appreciate your suggestions, but I have a doubt, how does 'regularly check/call' translate into code ?
It entirely depends on the task that the Runnable.run() method performs. It typically entails adding a check / call to certain loops so that the test happens reasonably often ... but not too often. You also want to check only when it would be safe to stop the computation, and that is another thing you must work out for yourself.
The following should help to give you some ideas of how you might apply it to your problem. Hope it helps...
import java.util.*;
public class x {
public static void main(String[] args) {
ThreadManager<Thread> t = new ThreadManager<Thread>();
Thread a = new MyThread(t);
Thread b = new MyThread(t);
Thread c = new MyThread(t);
t.add(a);
t.add(b);
t.add(c);
a.start();
b.start();
c.start();
}
}
class ThreadManager<T> extends ArrayList<T> {
public void stopThreads() {
for (T t : this) {
Thread thread = (Thread) t;
if (thread.isAlive()) {
try { thread.interrupt(); }
catch (Exception e) {/*ignore on purpose*/}
}
}
}
}
class MyThread extends Thread {
static boolean signalled = false;
private ThreadManager m;
public MyThread(ThreadManager tm) {
m = tm;
}
public void run() {
try {
// periodically check ...
if (this.interrupted()) throw new InterruptedException();
// do stuff
} catch (Exception e) {
synchronized(getClass()) {
if (!signalled) {
signalled = true;
m.stopThreads();
}
}
}
}
}
Whether you use a stop flag or an interrupt, you will need to periodically check to see whether a thread has been signalled to stop.
You could give them access to eachother, or a callback to something that had access to both so it could interrupt the other. Consider:
MyRunner aRunner = new MyRunner(this);
MyRunner bRunner = new MyRunner(this);
Thread a = new Thread(aRunner);
Thread b = new Thread(brunner);
// catch appropriate exceptions, error handling... probably should verify
// 'winner' actually is a or b
public void stopOtherThread(MyRunner winner) {
if(winner == aRunner ) bRunner .stop(); // assumes you have stop on class MyRunner
else aRunner.stop();
}
// later
a.start();
b.start();
// in your run method
public void run() {
// la de da de da
// awesome code
while(true) fork();
// other code here
myRunnerMaster.stopOtherThread(this);
}