当前位置: 首页 > 面试题库 >

AsyncTask一直在等待吗?

姬飞昂
2023-03-14
问题内容

我的一个活动中的一个按钮调用AsyncTask,该AsyncTask更新ListView的SimpleCursorAdapter的基础Cursor。每次单击按钮时,都会为AsyncTask添加一个新线程并完成任务(进入“等待”状态)。如果我单击按钮5次或更多次,则5个AsyncTasks最终以“等待”状态坐在那里。这是正常现象还是在某处内存泄漏?

AsyncTask

private class updateAdapter extends AsyncTask<Void, Void, Void> {

    @Override
    protected Void doInBackground(Void... params) {
        // Open database connection
        if(_db == null || !_db.isOpen()) _db = new DatabaseWrapper(ActivityShowWOD.this).getWritableDatabase();
        Cursor WODcursor;

        // Check if a wod_id is set
        if(_wod_id == -1) {
            // Grab filters from preferences and at the same time build SQLselection string
            SharedPreferences prefs = getSharedPreferences("Preferences", 0);
            String[] filterNames = getResources().getStringArray(R.array.filters_values);
            boolean[] filterValues = new boolean[filterNames.length];
            String SQLselection = "";

            for (int i = 0; i < filterNames.length; i++) {
                filterValues[i] = prefs.getBoolean(filterNames[i], false);

                // Build SQL query
                if(filterValues[i] == true) {
                    SQLselection += filterNames[i] + " = 1 OR " +  filterNames[i] + " = 0";
                } else {
                    SQLselection += filterNames[i] + " = 0";
                }

                // Add an "AND" if there are more filters 
                if(i < filterNames.length - 1) SQLselection += " AND ";
            }

            // Get all WODs matching filter preferences 
            WODcursor = _db.query(DatabaseConstants.TBL_WORKOUTS, 
                                      new String[] { DatabaseConstants.WORKOUTS_ID, DatabaseConstants.WORKOUTS_NAME,
                                                     DatabaseConstants.WORKOUTS_NOTES, DatabaseConstants.WORKOUTS_CFID }, 
                                      SQLselection, null, null, null, null);

            // Move the Cursor to a random position
            Random rand = new Random();
            WODcursor.moveToPosition(rand.nextInt(WODcursor.getCount()));

            // Store wod_id
            _wod_id = WODcursor.getInt(WODcursor.getColumnIndex(DatabaseConstants.WORKOUTS_ID));
        } else {
            // Get the cursor from the wod_id
            WODcursor = _db.query(DatabaseConstants.TBL_WORKOUTS, 
                                 new String[] { DatabaseConstants.WORKOUTS_ID, DatabaseConstants.WORKOUTS_NAME,
                                                DatabaseConstants.WORKOUTS_NOTES, DatabaseConstants.WORKOUTS_CFID }, 
                                 DatabaseConstants.WORKOUTS_ID + " = " + _wod_id, null, null, null, null);

            WODcursor.moveToFirst();
        }

        // Store WOD information into class instance variables and close cursor
        _wod_cfid = WODcursor.getInt(WODcursor.getColumnIndex(DatabaseConstants.WORKOUTS_CFID));
        _wod_name = WODcursor.getString(WODcursor.getColumnIndex(DatabaseConstants.WORKOUTS_NAME));
        _wod_notes = WODcursor.getString(WODcursor.getColumnIndex(DatabaseConstants.WORKOUTS_NOTES));
        WODcursor.close();

        // Return all exercises pertaining to this WOD
        _excCursor = _db.query(DatabaseConstants.TBL_EXERCISES, 
                              new String[] { DatabaseConstants.EXERCISES_ID, DatabaseConstants.EXERCISES_EXERCISE,
                                             DatabaseConstants.EXERCISES_REPS, DatabaseConstants.EXERCISES_NOTES }, 
                              DatabaseConstants.EXERCISES_WOD_ID + " = " + _wod_id, null, null, null, 
                              DatabaseConstants.EXERCISES_ID + " ASC");
        return null;
    }

    @Override
    protected void onPostExecute(Void result) {
        _adapter.changeCursor(_excCursor);
        _adapter.notifyDataSetChanged();
        _WODlist.setOnItemClickListener(new WODlistClickListener());
    }

}

还有我的onCreate中调用任务的代码(首次加载活动时):

upAdapter = new updateAdapter().execute();

并在按钮onClickListener中:

            // Reset wod_id
            _wod_id = -1;

            // Update the underlying SimpleCursorAdapter
            upAdapter = new updateAdapter().execute();

AsyncTask之一的堆栈跟踪(所有这些都相同):

Object.wait(long, int) line: not available [native method]  
Thread.parkFor(long) line: 1535 
LangAccessImpl.parkFor(long) line: 48   
Unsafe.park(boolean, long) line: 317    
LockSupport.park() line: 131    
AbstractQueuedSynchronizer$ConditionObject.await() line: 1996   
LinkedBlockingQueue.take() line: 359    
ThreadPoolExecutor.getTask() line: 1001 
ThreadPoolExecutor.runWorker(ThreadPoolExecutor$Worker) line: 1061  
ThreadPoolExecutor$Worker.run() line: 561   
Thread.run() line: 1096

问题答案:

AsyncTask引擎盖下使用一个ThreadPoolExecutor。这些线程可能不会消失一点,因为过于频繁地创建和拆除这些线程是一种浪费。过一会儿,如果您创建更多AsyncTasks线程,您会发现它将停止创建新线程,并将重新使用旧线程。

更新以解决一些细节:

您可能会认为,如果池中有空闲线程,则不会创建新线程,但这并非完全正确。这个想法是,有一定数量的线程对于保持处理异步任务很有用。这称为核心池大小。在Android的AsyncTask情况下,他们似乎已将其设置为5。如果您查看ThreadPoolExecutor它的文档说:

当在方法execute(Runnable)中提交新任务,并且正在运行的线程少于corePoolSize线程时,即使其他工作线程处于空闲状态,也会创建一个新线程来处理请求。

还有一个最大值适当地称为最大池大小。



 类似资料:
  • 问题内容: 我通过将操作拆分为可用的确切内核数来并行化操作,然后通过启动相同数量的AsyncTask,对数据的不同部分执行相同的操作。 我正在使用以并行化它们的执行。 我想知道每个线程何时完成其工作,以便结合所有结果并执行进一步的操作。 我能怎么做? 问题答案: 您还可以简单地将共享库中的计数器递减作为的一部分。由于在同一线程(主线程)上运行,因此您不必担心同步。 更新1 共享对象可能看起来像这样

  • 根据Espresso文档,检测测试应该自动等待完成。但它不起作用。我创建了这个简单的测试用例: 返回UI线程时测试应该失败,但它总是成功。这是测试的logcat输出: 正如您所看到的,测试在后台方法执行之前就已经完成了。我怎样才能让考试等待呢?

  • 问题内容: 我在Python 2.7中使用selenium,并且有以下代码,但是我正在寻找一种更有效的方法: 问题答案: 您无需使用一段时间。它已经等待您在WebDriverWait()函数中显示的时间。

  • 问题内容: 我正在开发Chrome中的扩展程序,但我想知道:找出元素何时存在的最佳方法是什么?使用纯JavaScript,间隔检查直到元素存在,或者jQuery是否有一些简单的方法来执行此操作? 问题答案: 由于性能问题,不建议将其与其他DOM突变事件一起弃用- 推荐的方法是使用MutationObserver来监视DOM。不过,只有新的浏览器才支持此功能,因此您应该在不可用时退回。

  • 问题内容: 如何让我的代码等待,直到DispatchQueue中的任务完成?是否需要任何CompletionHandler或其他东西? 我正在使用Xcode 8.2并在Swift 3中编写。 问题答案: 使用s可以实现这一点。您可以在群组和通话达到平衡时得到通知: 或者您可以等待: 注意 :阻止当前队列(在您的情况下可能是主队列),因此您必须在另一个队列上(如上面的示例代码中)以避免 死锁 。

  • 我使用等待块使代理等待,直到条件为真(资源空闲)。我尝试在等待块“输入”字段中写入以下内容: 问题是,如果资源变得繁忙,代理将被困在等待块中,不会被释放,即使条件再次变为真。然后,当下一个代理进入等待块时(条件再次变为真),它将传递原本在它前面的代理,但现在被卡住了。有办法解决这个问题吗?