2015-06-20 9 views
6

Jestem nowy w tym równoległym programowaniu w Javie i wymyśliłem następujące scenariusze, w których pojawia się dezorientacja, której należy użyć, kiedy.

Scenariusz 1: W poniższym kodzie starałem się uruchomić wątki wywołując .start() od klasy GPSService który jest Runnable realizacja.Jaka jest różnica między wykonywaniem ExecutorService i thread.run w uruchomionych wątkach jednocześnie w Javie?

int clientNumber = 0; 
ServerSocket listener = new ServerSocket(port); 

while (true) { 
      new GPSService(listener.accept(), clientNumber++, serverUrl).start(); 
} 

Scenariusz 2: W poniższym kodzie starałem się uruchomić wątki za pomocą klasy ExecutorService jak pokazano

int clientNumber = 0; 
ServerSocket listener = new ServerSocket(port); 
while(true) { 
     ExecutorService executor = Executors.newSingleThreadExecutor(); 
     executor.execute(new GPSService(listener.accept(), client++, serverUrl)); 

     executor.shutdown(); 
     while (!executor.awaitTermination(1, TimeUnit.SECONDS)) { 
      // Threads are still running 
      System.out.println("Thread is still running"); 
     } 
     // All threads are completed 
     System.out.println("\nThread completed it's execution and terminated successfully\n");    
} 

Moje pytania są
Która jest najlepsza praktyka, aby wywołać wątek w współbieżne programowanie?
Jaki będzie wynik (kłopoty), na które napewno skorzystam, gdy użyję pierwszego lub drugiego?
Uwaga: Miałem do czynienia z problemem z pierwszym scenariuszem, w którym program jest zawieszany po kilku dniach. Czy ta kwestia jest związana/oczekiwana, gdy używam pierwszej metody?
Każdy dobry jako odpowiedź/zostaną docenione :) Dziękuję

+0

możliwe duplikat [puli wątków vs tarła wątku] (http://stackoverflow.com/questions/2049948/thread-pool-vs-thread (odradza się) –

+0

@NarendraPathai Jestem bardziej konkretny na moje pytanie, jeśli tak, jak możesz oznaczyć je jako duplikat ??? –

+0

@NarendraPathai Wspomniałem właśnie o tym, żeby się dowiedzieć, czy FirstScenario ma możliwość wywołania takich problemów. Dla twojego zrozumienia, nie poprosiłem o rozwiązanie tego wiszącego problemu. I dziękuję za referencję –

Odpowiedz

3

Nie ma dużych różnic w dwóch scenariusza pisał, z wyjątkiem zarządzania zakończenie gwintu w Scenario2; zawsze tworzysz nowy wątek dla każdego przychodzącego żądania. Jeśli chcesz używać ThreadPool, moja rada nie polega na tworzeniu dla każdego żądania, ale na tworzeniu dla każdego serwera i ponownym użyciu wątków. Coś takiego:

public class YourClass { 

//in init method or constructor 
ExecutorService executor = Executors....;// choose from newCachedThreadPool() or newFixedThreadPool(int nThreads) or some custom option 


int clientNumber = 0; 
ServerSocket listener = new ServerSocket(port); 
while(true) { 

    executor.execute(new GPSService(listener.accept(), client++, serverUrl)); 

} 

Pozwoli to na korzystanie z puli wątków i kontrolowanie liczby wątków używanych na serwerze. Jeśli chcesz użyć Executora, jest to preferowana metoda.

Przy puli serwerów musisz zdecydować, ile wątków jest w puli; masz różne możliwości, ale możesz zacząć lub z ustaloną liczbą lub wątkami lub z pulą, która próbuje użyć wątku nieobsługiwanego i jeśli wszystkie wątki są zajęte, tworzy nowy (newCachedThreadPool()). Liczba wątków do przydzielenia zależy od wielu czynników: liczby żądań współbieżnych i czasu trwania. Im więcej kodu po stronie serwera wymaga czasu, tym więcej potrzebujesz do dodatkowego wątku. Jeśli twój kod po stronie serwera jest bardzo szybki, istnieje bardzo duża szansa, że ​​pula może ponownie przetwarzać wątki już przydzielone (ponieważ żądania nie przychodzą dokładnie w tym samym momencie).

Powiedzmy na przykład, że masz 10 żądań podczas sekundy, a każde żądanie trwa 0,2 sekundy; jeśli wniosek dotrze do 0, 0,1, 0,2, 0,3, 0,4, 0,5, .. część drugiego (na przykład 23/06/2015 7: 16: 00: 00, 23/06/2015 7:16:00: 01, 23/06/2015 7: 16: 00: 02) potrzebujesz tylko trzech wątków, ponieważ żądanie przychodzące na 0.3 może być wykonane przez wątek, który serwer pierwszy wniosek (ten na 0), i tak dalej (żądanie w czasie 0,4 może ponownie użyć wątku używanego do żądania, które pochodziło z poziomu 0,1). Dziesięć żądań zarządzanych przez trzy wątki.

Polecam (jeśli jeszcze tego nie zrobiłeś) przeczytanie Java Współbieżność w praktyce (Wykonanie Zadań to rozdział 6); co jest świetną książką na temat tworzenia współbieżnej aplikacji w Javie.

+0

Więc jeśli używam newCachedThreadPool() lub newFixedThreadPool (int nThreads), ponieważ otrzymuję dane co cztery sekundy od setek klientów, czy nie będę miał problemów z używać pojedynczego wątku dla każdego klienta? –

+1

Nie ma problemów, jeśli uda się poprawnie dopasować wielkość puli, przy pomocy newCachedThreadPool() nie utworzyłeś nawet górnego limitu na wątku o numerze – Giovanni

1

Oracle documentation z Executors

public static ExecutorService newCachedThreadPool() 

Tworzy puli wątków, które tworzy nowe wątki w miarę potrzeb, ale będzie ponownego użycia wcześniej skonstruowane wątki gdy są one dostępne. Pule te zazwyczaj poprawiają wydajność programów wykonujących wiele krótkotrwałych zadań asynchronicznych.

Wywołania do wykonania ponownie wykorzystają wcześniej utworzone wątki, jeśli są dostępne. Jeśli żaden istniejący wątek nie jest dostępny, nowy wątek zostanie utworzony i dodany do puli. Wątki, które nie były używane przez sześćdziesiąt sekund, są usuwane i usuwane z pamięci podręcznej.

W ten sposób pula, która pozostaje bezczynna przez wystarczająco długi czas, nie zużyje żadnych zasobów. Należy zauważyć, że pule o podobnych właściwościach, ale różnych szczegółach (na przykład parametry limitu czasu) mogą być tworzone za pomocą konstruktorów ThreadPoolExecutor.

public static ExecutorService newFixedThreadPool(int nThreads) 

Tworzy puli wątków, które ponownie wykorzystuje ustaloną liczbę wątków działających poza wspólną kolejce nieograniczonego. W dowolnym momencie wątki nThreads będą aktywnymi zadaniami przetwarzania. Jeśli dodatkowe zadania zostaną przesłane, gdy wszystkie wątki będą aktywne, będą czekały w kolejce, dopóki wątek nie będzie dostępny.

Jeśli jakikolwiek wątek zakończy się z powodu awarii podczas wykonywania przed zamknięciem, nowy zajmie jego miejsce, jeśli będzie to konieczne do wykonania kolejnych zadań. Wątki w puli będą istniały, dopóki nie zostaną jawnie zamknięte.

@Giovanni mówi, że ty nie musiał dostarczyć liczbę wątków do newCachedThreadPool przeciwieństwie newFixedThreadPool(), gdzie trzeba przejść maksymalnego limitu na liczbę wątków w puli wątków.

Ale pomiędzy tymi dwoma preferowane jest newFixedThreadPool(). newCachedThread Pool może powodować nieszczelność, a użytkownik może osiągnąć maksymalną liczbę dostępnych wątków ze względu na nieograniczony charakter. Niektórzy uważają to za zło.

Wystarczy popatrzeć na powiązanego SE pytanie:

Why is an ExecutorService created via newCachedThreadPool evil?

+0

Podczas korzystania z newFixedThreadPool(), w jaki sposób możesz ustalić, który numer ma być używany w wątkach. – Jesse

+0

Rozpocznij od Runtime.getRuntime(). AvailableProcessors() –

Powiązane problemy