O AsyncTask usa um padrão de conjunto de encadeamentos para executar as coisas de doInBackground (). O problema é inicialmente (nas primeiras versões do sistema operacional Android) o tamanho do pool era apenas 1, o que significa que não há cálculos paralelos para várias tarefas AsyncTasks. Porém, mais tarde, eles corrigiram isso e agora o tamanho é 5, portanto, no máximo, 5 AsyncTasks podem ser executadas simultaneamente. Infelizmente, não me lembro em que versão exatamente eles mudaram isso.
ATUALIZAR:
Aqui está o que a API atual (2012-01-27) diz sobre isso:
Quando introduzidas pela primeira vez, as AsyncTasks foram executadas em série em um único encadeamento em segundo plano. Começando com DONUT, isso foi alterado para um pool de threads, permitindo que várias tarefas operassem em paralelo. Após o HONEYCOMB, está planejado alterar isso de volta para um único encadeamento para evitar erros comuns de aplicativo causados pela execução paralela. Se você realmente deseja execução paralela, pode usar a versão executeOnExecutor (Executor, Params ...) deste método com THREAD_POOL_EXECUTOR; no entanto, consulte os comentários para avisos sobre seu uso.
DONUT é o Android 1.6, HONEYCOMB é o Android 3.0.
UPDATE: 2
Veja o comentário kabuko
de Mar 7 2012 at 1:27
.
Acontece que, para APIs em que "um conjunto de threads que permite que várias tarefas operem em paralelo" é usado (a partir de 1.6 e finalizando em 3.0), o número de AsyncTasks em execução simultânea depende de quantas tarefas já foram passadas para execução, mas ainda não terminaram o seu doInBackground()
.
Isso é testado / confirmado por mim em 2.2. Suponha que você tenha um AsyncTask personalizado que durma apenas um segundo doInBackground()
. AsyncTasks usam internamente uma fila de tamanho fixo para armazenar tarefas atrasadas. O tamanho da fila é 10 por padrão. Se você iniciar 15 suas tarefas personalizadas em uma linha, as 5 primeiras entrarão com as deles doInBackground()
, mas o restante aguardará na fila por um encadeamento de trabalho livre. Assim que qualquer um dos 5 primeiros for concluído e, assim, liberar um thread de trabalho, uma tarefa da fila iniciará a execução. Portanto, neste caso, no máximo 5 tarefas serão executadas simultaneamente. No entanto, se você iniciar 16 suas tarefas personalizadas consecutivas, as 5 primeiras entrarão nas suas doInBackground()
, as 10 restantes entrarão na fila, mas no dia 16 será criado um novo encadeamento de trabalho para iniciar a execução imediatamente. Portanto, neste caso, no máximo 6 tarefas serão executadas simultaneamente.
Há um limite de quantas tarefas podem ser executadas simultaneamente. Como AsyncTask
usa um executor de conjunto de encadeamentos com número máximo limitado de encadeamentos de trabalho (128) e a fila de tarefas atrasadas tem tamanho 10 fixo, se você tentar executar mais de 138 suas tarefas personalizadas, o aplicativo falhará java.util.concurrent.RejectedExecutionException
.
A partir do 3.0, a API permite usar o executor do conjunto de threads personalizado por meio do AsyncTask.executeOnExecutor(Executor exec, Params... params)
método Isso permite, por exemplo, configurar o tamanho da fila de tarefas atrasadas se o padrão 10 não for o que você precisa.
Como o @Knossos menciona, existe uma opção para usar AsyncTaskCompat.executeParallel(task, params);
na biblioteca de suporte v.4 para executar tarefas em paralelo sem se preocupar com o nível da API. Este método foi descontinuado no nível da API 26.0.0.
UPDATE: 3
Aqui está um aplicativo de teste simples para jogar com o número de tarefas, execução serial versus paralela: https://github.com/vitkhudenko/test_asynctask
ATUALIZAÇÃO: 4 (obrigado @penkzhou por apontar isso)
A partir do Android 4.4 AsyncTask
se comporta de maneira diferente da descrita na seção UPDATE: 2 . Há uma correção para impedir a AsyncTask
criação de muitos threads.
Antes do Android 4.4 (API 19), AsyncTask
havia os seguintes campos:
private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 128;
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(10);
No Android 4.4 (API 19), os campos acima são alterados para isso:
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private static final int CORE_POOL_SIZE = CPU_COUNT + 1;
private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1;
private static final BlockingQueue<Runnable> sPoolWorkQueue =
new LinkedBlockingQueue<Runnable>(128);
Essa alteração aumenta o tamanho da fila para 128 itens e reduz o número máximo de threads ao número de núcleos da CPU * 2 + 1. Os aplicativos ainda podem enviar o mesmo número de tarefas.