4

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

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

while(go) {
 f();
}

终结器是:

public void finalize() {
 go = false;
}

当对象的所有外部引用都被删除时,AsyncTask 会停止吗?或者系统会继续线程,永远不会删除对象,因为它被线程引用?

4

3 回答 3

2

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

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

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

于 2012-08-19T05:22:16.037 回答
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...

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

于 2012-08-19T05:08:48.697 回答
0

我认为 AsyncTask 永远不会停止,因为您正在这样做 : go = false;,在while循环之外。只有当go条件变为false, 在循环内时,该循环才会停止。执行上面写的循环,go条件永远不会更新,while 循环将只检查go变量的初始状态。看看这个SO question。

一个正确的 while 循环示例:

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

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

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

于 2012-08-18T12:42:36.230 回答