4

A quick theoretical question. Suppose I have a Java class which makes use of both a finalizer and an instance of its own private AsyncTask not referenced anywhere else.

Now suppose the AsyncTask's doInBackground method is something like:

while(go) {
 f();
}

and the finalizer is:

public void finalize() {
 go = false;
}

When all external references to the object are deleted, will the AsyncTask be stopped? Or will the system continue with the thread, never deleting the object because it is referenced by the thread?

mimicocotopus
  • 5,280
  • 4
  • 22
  • 24

3 Answers3

2

Can I rely on the garbage collector to stop an AsyncTask?

No you can't. In fact, you can rely on the GC NOT stopping the task.

The GC will only finalize an object that has become unreachable. But all active threads are reachable by definition, and that means that the AsyncTask object will also be reachable.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
1

Short answer: the thread keeps going, you can't rely on the GC to stop it.

Details: Not being able to get a sufficient answer to my question (thank you however, Alberto) I decided to test this out empirically by myself. Using the following test code:

public class TestActivity extends Activity {
   private ThreadContainer mtc;

   public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);

      setContentView(R.layout.main);

      mtc = new ThreadContainer();
   }

   public void btnFree_click(View view) {
      Log.v("TestActivity","Free clicked");
      mtc = null;
   }
}

public class ThreadContainer {
   private boolean go = true;

   public ThreadContainer() {
      new testThread().execute(1);
   }

   private class testThread extends AsyncTask<Integer,Integer,Integer> {
      protected Integer doInBackground(Integer... arg0) {
        while(go) {
          Log.v("testThread","I'm running...");

          try {
            Thread.sleep(500);
          } catch (InterruptedException e) {
            // do nothing
          }
       }

     return 0;
      }
  }

  @Override
  public void finalize() {
      go = false;
  }
}

I was able to get the following output from logcat:

I/ActivityManager(  244): Displayed com.example.test/.TestActivity: +509ms
V/testThread(13728): I'm running...
V/testThread(13728): I'm running...
V/testThread(13728): I'm running...
V/testThread(13728): I'm running...
V/testThread(13728): I'm running...
V/testThread(13728): I'm running...
V/testThread(13728): I'm running...
V/testThread(13728): I'm running...
V/testThread(13728): I'm running...
V/testThread(13728): I'm running...
V/TestActivity(13728): Free clicked
D/dalvikvm(  512): GC_EXPLICIT freed 144K, 50% free 2891K/5767K, external 1685K/2133K, paused 164ms
V/testThread(13728): I'm running...
V/testThread(13728): I'm running...
V/testThread(13728): I'm running...
V/testThread(13728): I'm running...
V/testThread(13728): I'm running...
V/testThread(13728): I'm running...
V/testThread(13728): I'm running...
V/testThread(13728): I'm running...
V/testThread(13728): I'm running...
V/testThread(13728): I'm running...
D/dalvikvm(13449): GC_EXPLICIT freed 12K, 47% free 2894K/5379K, external 1685K/2133K, paused 94ms
V/testThread(13728): I'm running...
V/testThread(13728): I'm running...
V/testThread(13728): I'm running...
V/testThread(13728): I'm running...
V/testThread(13728): I'm running...

As you can see the thread is not stopped, even though its task is completely private and there are no longer any external references to its container object.

mimicocotopus
  • 5,280
  • 4
  • 22
  • 24
0

I think the AsyncTask will never be stopped, because you're doing this : go = false;, out of the while loop. That loop will stop only when the go condition changes to false, within the loop. Executing the loop as you wrote above, the go conditon will never be updated and the while loop will check only the initial state of the go variable. Take a look to this SO question.

An example of a right while loop:

class WhileDemo {
    public static void main(String[] args){
        int count = 1;
        while (count < 11) {
            System.out.println("Count is: "
                               + count);
            count++;
        }
    }
}

This won't be an endless loop, because we are changing the while condition within the loop. You can also use the break statement to exit the loop in the correct way.

Another consideration. If the AsyncTask is marked as a daemon thread, when all the external references to the object are deleted, the system should stop the thread. Further details about daemon threads here and here.

Community
  • 1
  • 1
Alberto Solano
  • 7,972
  • 3
  • 38
  • 61
  • I should clarify. In this example, _go_ is a private member of the class which holds both the AsyncTask and the finalizer, so each iteration of the _while_ is referencing the variable which is to be changed by the finalizer. – mimicocotopus Aug 18 '12 at 13:14
  • Yes, I understand. If you are running the application in this way, you will have an endless loop. Then, unless you change the condition within the while loop, the AsyncTask will never be marked as finalizable by the GC. – Alberto Solano Aug 19 '12 at 17:00
  • I would know the reason of downvoting my answer. It was confirmed also by @mimicocotopus. Why? – Alberto Solano Aug 20 '12 at 07:39