我可以依靠垃圾收集器来停止AsyncTask吗?

时间:2012-08-18 12:25:08

标签: java android garbage-collection

一个快速的理论问题。假设我有一个Java类,它使用了终结器和它自己的私有AsyncTask的实例,而不是在其他任何地方引用它。

现在假设AsyncTask的doInBackground方法类似于:

while(go) {
 f();
}

,终结者是:

public void finalize() {
 go = false;
}

当删除对该对象的所有外部引用时,是否会停止AsyncTask?或者系统是否继续使用该线程,从不删除该对象,因为它是由线程引用的?

3 个答案:

答案 0 :(得分:2)

  

我可以依靠垃圾收集器来停止AsyncTask吗?

不,你不能。实际上,您可以依靠GC NOT 停止任务。

GC只会完成一个无法访问的对象。但是根据定义,所有活动线程都可以访问,这意味着AsyncTask对象也可以访问。

答案 1 :(得分:1)

简短回答:线程继续,你不能依靠GC来阻止它。

详细信息:无法对我的问题给出足够的答案(但是,谢谢你,Alberto)我决定自己凭经验测试这个问题。使用以下测试代码:

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;
  }
}

我能从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...

正如您所看到的,线程未停止,即使其任务完全是私有的,并且不再对其容器对象进行任何外部引用。

答案 2 :(得分:0)

我认为AsyncTask永远不会停止,因为你在go = false;循环中执行此操作:while。只有当go条件在循环内变为false时,该循环才会停止。如上所述执行循环,go条件永远不会更新,而while循环只会检查go变量的初始状态。看看this问题。

右边循环的example

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

这不会是无限循环,因为我们正在改变循环中的while条件。 您还可以使用break语句以正确的方式退出循环。

另一个考虑因素。如果AsyncTask被标记为守护程序线程,则当删除对该对象的所有外部引用时,系统应该停止该线程。有关守护程序线程herehere的更多详细信息。