Wątki AsyncTask nigdy nie umierają

112

Używam AsyncTasks do pobierania danych w odpowiedzi na naciśnięcie przycisku przez użytkownika. Działa to dobrze i utrzymuje responsywność interfejsu podczas pobierania danych, ale kiedy sprawdzałem, co się dzieje w debugerze Eclipse, stwierdzałem, że za każdym razem, gdy AsyncTasktworzony był nowy (co jest dość często, ponieważ można ich użyć tylko raz ), nowy wątek był tworzony, ale nigdy nie został zakończony.

W rezultacie AsyncTaskpo prostu siedzi tam duża liczba wątków. Nie jestem pewien, czy jest to problem w praktyce, czy nie, ale naprawdę chciałbym pozbyć się tych dodatkowych wątków.

Jak mogę zabić te wątki?

Komputerowe
źródło
Co masz na myśli mówiąc „nigdy nie zakończono”? Czy zadanie nigdy nie kończy swojej metody doInbackground, czy po prostu widzisz obiekt asynctask w narzędziu do śledzenia alokacji?
Francesco Laurita
7
doInBackgroundMetoda kończy, ale wątek nadal pojawiają się w oknie debugowania. Na przykład: Thread [<23> AsyncTask #4](Running)
Computerish

Odpowiedzi:

202

AsyncTaskzarządza pulą wątków utworzoną za pomocą ThreadPoolExecutor. Będzie miał od 5 do 128 wątków. Jeśli jest więcej niż 5 wątków, te dodatkowe wątki będą trzymać się maksymalnie przez 10 sekund, zanim zostaną usunięte. (Uwaga: te liczby dotyczą obecnie widocznego kodu open source i różnią się w zależności od wersji Androida).

Zostaw AsyncTaskwątki w spokoju.

CommonsWare
źródło
Dziękuję za wyjaśnienie! Cieszę się, że nie robię nic złego. Z ciekawości, dlaczego jest tak zaprojektowany? Dlaczego po prostu nie zakończyć wątków po zwróceniu wszystkich metod?
Computerish
7
Prawdopodobnie w celu zaoszczędzenia czasu na rozwidlanie wątków w późniejszych żądaniach.
CommonsWare
@CommonsWare Mam usługę, w której uruchamiam AsyncTask, aby wykonać jakąś operację, a usługa uruchamia się po naciśnięciu przycisku widżetu i po zakończeniu zadania musi natychmiast zatrzymać usługę, ale czasami AsyncTask nie umrze, więc możesz powiedz mi, jak mam to zatrzymać
Hunt
1
@SreekanthKarumanaghat: Używanie AsyncTaskdo czegoś, co zajęłoby tak długo, jest ogólnie złym pomysłem. Ale nie, mój komentarz dotyczący dodatkowych wątków odchodzących jest wtedy, gdy są nieużywane. Zatem po zakończeniu jednego z 6 zadań jego wątek pozostanie w puli przez 10 sekund, po czym ten wątek zostanie zakończony.
CommonsWare
1
@SreekanthKarumanaghat: "Moje pytanie brzmi, czy istnieją jakieś ograniczenia dotyczące uruchamiania 20 (powiedzmy) zadań AsyncTask równolegle?" - Znaczące wykorzystanie AsyncTaskdzisiejszego dnia nie jest wielkim planem. Posiadanie 20+, które mogą działać przez ponad 10 sekund, to coś, co powinno zakończyć się niepowodzeniem podczas przeglądu kodu. Jeśli utworzysz 20 zadań w krótkim odstępie czasu, tylko kilka zostanie uruchomionych naraz, a reszta zostanie umieszczona w kolejce do późniejszego wykonania. To, ile będzie działać na raz, zależy od liczby rdzeni procesora. AFAIK, obecny algorytm to 2N + 1 równoległych wątków, gdzie N to liczba rdzeni.
CommonsWare
24

Oprócz odpowiedzi CommonsWare:

Obecnie używam Androida 2.2, a moja aplikacja używa nie więcej niż jednego AsyncTask w dowolnym momencie, ale tworzę nowe co x minut. Na początku pojawiają się nowe wątki AsyncTask (nowy wątek dla nowego AsyncTask), ale po 5 wątkach (jak wspomniał CommonsWare) pozostają one widoczne w oknie debugowania i są ponownie używane, gdy potrzebne są nowe wątki AsyncTask. Po prostu pozostają tam, dopóki debugger się nie rozłączy.

Tom de Waard
źródło
2
Tak, potwierdzono: nie widzę więcej niż 5 AsyncTasks.
Seraphim's
3

Ten sam symptom tutaj. W moim przypadku wątki zawisły po tym, jak zabiłem działanie i miałem nadzieję, że aplikacja zostanie całkowicie zamknięta. Problem częściowo rozwiązany za pomocą jednowątkowego executora:

    myActiveTask.executeOnExecutor(Executors.newSingleThreadExecutor());

To sprawiło, że nić zniknęła po zakończeniu pracy.

karnbo
źródło
Ta odpowiedź sprawiła, że ​​AsyncTask zniknął po uruchomieniu, być może nie jest to „sposób Google na robienie rzeczy”, ale wykonuje swoją pracę. Dziękuję Ci.
Henrique de Sousa
To rozwiązało mój konkretny problem dotyczący uruchamiania Asynctasks na jednym wątku.
Law Gimenez
0

Użyj ThreadPoolExecutor .

BlockingQueue workQueue= new LinkedBlockingQueue<Runnable>(100); // Work pool size
ThreadPoolExecutor executor = new ThreadPoolExecutor(
            Runtime.getRuntime().availableProcessors(),       // Initial pool size
            Runtime.getRuntime().availableProcessors(),       // Max pool size
            1, // KEEP_ALIVE_TIME
            TimeUnit.SECONDS, //  KEEP_ALIVE_TIME_UNIT
            workQueue);

Opublikuj swoje Runnablezadanie za pomocą metody execute () .

void execute (Runnable command)

Wykonuje dane zadanie w przyszłości. Zadanie może zostać wykonane w nowym wątku lub w istniejącym wątku w puli

Odnośnie drugiego zapytania:

Jak mogę zabić te wątki?

Gdy skończysz z całą swoją pracą ThreadPoolExecutor, zamknij ją prawidłowo, jak podano w poniższym poście:

Jak prawidłowo zamknąć java ExecutorService

Ravindra babu
źródło