views:

156

answers:

3

I have a class that extends the Thread class and has its run method implemented as so.

public void run(){
    while(!terminate){
        if(paused){
            Thread.yield();
        }else{
            accummulator++;
        }
    }
}

This thread is spawned from the onCreate method.

When my UI is hidden (when the Home key is pressed) my onPause method will set the paused flag to true and yield the tread. However in the DDMS I still see the uTime of the thread accumulate and its state as "running".

So my question is. What is the proper way to stop the thread so that it does not use up CPU time?

A: 

Your paused variable is most likely being cached thread-locally. This is because it's only being read and not changed in the loop. So what is happening is that compiler/interpreter/jitter optimizes by only reading the variable once and then only executing the else branch. You need to mark that field as volatile for the pause variable to be read every iteration through the loop. Check out the documentation of the volatile keyword. Here's some info about threading and some info about synchronization and concurrency.

Qberticus
I'm not so much worried about the paused variable occupying resources. I'm wore worried that the thread is still looping even though the UI thread has stopped.
Kwan Cheng
I've updated the answer to more clearly explain what is happening. The answer wasn't about the pause variable and resources. The thread is still looping because the paused variable isn't marked as volatile and not being re-read. This is just one of the subtleties of multi-threaded programming.
Qberticus
+1  A: 

Even though you're calling thread.yield(), you're inside of a while() loop which is probably looping thousands of time per second, each time calling .yield() but the fact that it's looping out of control means that it's using up resources. If you put a Log.d message in there you'll see what I mean.

I recommend using a Thread.sleep() instead of Thread.yield(). The reason being, while a thread is sleeping it is yielded. Plus with the sleep you get the added benefit of slowing down the while() and not using up resources. A sleep interval of 500ms should be sufficient =)

Brad Hein
the thread will eventually be used as a render thread on a Canvas and it should execute as fast as possible. I think I'm going to try killing the thread and recreating it in the onresume handler
Kwan Cheng
Fair enough. It's worth emphasizing that closed loops like the one in your code are CPU hogs. On a mobile device, a cpu hog will eat up the battery in a hurry.
Brad Hein
+1  A: 

It is actually bad practice to keep a thread running after onPause. The reason is that after onPause your application may drop out of memory at any time without your being able to know, therefore you will not be able to clean up after yourself.

The proper way to do it is stopping the thread onPause and recreating it onResume. If you need state you can use Android's built in saveState methods or settings or whichever to keep that.

Moncader
Yes, that's the conclusion I came up with as well. Additionally I think the best method of implementation is not to subclass from Thread directly but use the Runnable interface. This way you can kill the thread but still have the ability to "resume" it by instantiating another thread, without losing state. Granted that onDestroy or the application is not killed and recreated.
Kwan Cheng