2010-01-17 19 views
6

Wątki są często projektowane na dwa sposoby (see java tutorials): przez rozszerzenie klasy wątków lub przez wprowadzenie klasy Runnable. Tak czy inaczej, musisz określić, co będzie działało w wątku.Jak radzić sobie z wieloma wątkami w jednej klasie?

Zaprojektowałem klasę, adapter do zasobu online, który pobiera różne rodzaje informacji. Ta klasa składa się z metod takich jak getInformationOfTypeA() i getInformationOfTypeB(). Oba zawierają kod do połączenia z zasobami online, więc oba muszą być powiązane, aby uniknąć zakleszczeń.

Pytanie brzmi: jak mam to zaprojektować? Mogę to zrobić jak poniżej, ale mogę tylko: wdrożenie jednego

metodę
public class OnlineResourceAdapter implements Runnable { 

    public void run() { 
     //get stuff from resource 
     getInformationOfTypeA(); 
    } 

    public static void main(String args[]) { 
     (new Thread(new OnlineResourceAdapter())).start(); 
    } 

    public void getInformationOfTypeA(){ 
     //get information of type A 
    } 

    public void getInformationOfTypeB(){ 
     //get information of type B 
    } 

} 

Innym sposobem byłoby tworząc oddzielne klasy dla każdej metody, ale wydaje mi się nienaturalne.

Btw: Zajmuję mój wniosek w J2ME

UPDATE:

Dzięki waszej odpowiedzi myślę, że to jest najbardziej ubraniowy użyć czegoś podobnego następujących metod: jak

Co myślisz o tym:

public class OnlineResourceAdapter{ 
    public void getInformationOfTypeA(){ 
     Thread t = new Thread(new Runnable() {   
      public void run() { 
       //do stuff here 
      } 
     }); 
     t.start(); 
    } 

    public void getInformationOfTypeB(){ 
     Thread t = new Thread(new Runnable() {   
      public void run() { 
       //do stuff here 
      } 
     }); 
     t.start(); 
    } 
} 

Wha Czy myślisz o tym?

Odpowiedz

1

Dla każdej klasy utwórz anonimową klasę na podstawie Runnable. To pozwoli ci zrobić to, co musisz zrobić wewnątrz metody run().

6

Wydaje mi się, że powinieneś mieć dwie różne klasy: InformationOfTypeAFetcher i InformationOfTypeBFetcher, z których każda powinna implementować Runnable. Każdy z nich może mieć odniesienie do instancji twojego OnlineResourceAdapter (lub czegoś podobnego), ale jeśli robią różne rzeczy, powinny być różnymi klasami.

1

Nie rozumiem, dlaczego nie podoba Ci się pomysł tworzenia wielu klas, biorąc pod uwagę, że Java nie obsługuje funkcji wyższego rzędu, a zmienną częścią kodu jest algorytm.

Ale jeśli chciał pojedynczą realizację od OnlineResourceAdapter można użyć wzoru strategii i zrobić coś takiego:

public interface InformationGetter { 
    public void getInformation(); 
} 

public class OnlineResourceAdapter implements Runnable { 
    private final InformationGetter informationGetter; 

    public OnlineResourceAdapter(InformationGetter i) { 
    this.informationGetter = i; 
    } 

    public void run() { 
     //get stuff from resource 
     i.getInformation(); 
    } 
} 

i wtedy oczywiście można utworzyć dowolną liczbę implementacje InformationGetter jak potrzebne.

Przyjdź, pomyśl o tym, patrząc wstecz na to podejście, OnlineResourceAdapter teraz tak naprawdę nie dodaje nic oprócz robienia InformationGetter działającego. Więc jeśli nie masz jakiegoś przekonującego powodu, aby tego nie robić, powiedziałbym po prostu InformationGetter implementację Runnable bezpośrednio.

+0

danben powtarza moją opinię. Wzorzec strategii to jedna rzecz, na którą możesz chcieć spojrzeć. Posiadanie osobnych klas wygląda na czysty sposób w tym przypadku – Aadith

1

Wiele osób już zasugerowało dobre metody, jak to zrobić, używając kilku klas.Ponieważ wydaje się preferować taki sposób, który nie wymaga wiele klas, można również rozważyć użycie konstruktora, aby podać informacje, o których zasób, aby pobrać:

public class OnlineResourceAdapter implements Runnable 
{ 
    private string resourceType; 

    public OnlineResourceAdapter(string resourceType) 
    { 
     this.resourceType = resourceType; 
    } 

    public void run() { 
     if (resourceType.equals("A") { 
      getInformationOfTypeA(); 
     } else { 
      // etc.. 
     } 
    } 

    public void getInformationOfTypeA(){ 
     //get information of type A 
    } 

    public void getInformationOfTypeB(){ 
     //get information of type B 
    } 
} 

Zastosowanie:

(new Thread(new OnlineResourceAdapter("A"))).start(); 
+0

Jeśli naprawdę nie musisz, naprawdę nie rób tego. Im więcej możesz wpisać w statyczne pisanie, tym lepiej. Innymi słowy, mają dwie oddzielne klasy. –

+0

Z drugiej strony, jeśli masz potencjalnie tysiące typów informacji do pobrania lub typ informacji, które mają być odbierane to parametry wprowadzane przez użytkownika, metoda ta miałaby dużo większy sens, gdyby typ był parametrem constuctor niż tworzenie nowej klasy dla każdego typu. Nie wiedząc więcej o potrzebach plakatu, trudno jest powiedzieć, jakie jest najlepsze rozwiązanie. –

-1

Użyj anonimowe klasy typu Callable (które, w przeciwieństwie do Runnable, mogą zwracać wartości) i wykonywać je za pomocą Executor. Jeśli logika pobierania informacjiA i informacjiB jest bardzo podobna, możesz ją oczywiście refaktoryzować i używać pojedynczego, parametryzuje wewnętrzną klasę Wskaźników.

Nie jestem pewien, czy program Callable i Executor są częścią specyfikacji J2ME. W standardowej Javie i tak podążałbym za podejściem Proxy i hermetyzowałem zewnętrzny zasób jako interfejs.

public class AsyncMethodsTest { 

    public class OnlineResourceAdapter { 

     private final ExecutorService executor = Executors.newFixedThreadPool(2); 

     public String getInformationOfTypeA() throws InterruptedException, ExecutionException, 
       TimeoutException { 
      Callable<String> callable = new Callable<String>() { 
       @Override 
       public String call() throws Exception { 
        // Connect to external resource 
        Thread.sleep(500); 
        return "A"; 
       } 

      }; 
      Future<String> submit = executor.submit(callable); 
      return submit.get(1000, TimeUnit.MILLISECONDS); 
     } 

     public String getInformationOfTypeB() throws InterruptedException, ExecutionException, 
       TimeoutException { 
      Callable<String> callable = new Callable<String>() { 
       @Override 
       public String call() throws Exception { 
        // Connect to external resource 
        Thread.sleep(1500); 
        return "B"; 
       } 

      }; 
      Future<String> submit = executor.submit(callable); 
      return submit.get(1000, TimeUnit.MILLISECONDS); 
     } 

    } 

    @Test 
    public void testMethodCalls() throws Exception { 
     OnlineResourceAdapter adapter = new OnlineResourceAdapter(); 
     assertNotNull(adapter.getInformationOfTypeA()); 
     assertNotNull(adapter.getInformationOfTypeB()); 
    } 
} 
+1

Niestety, nie ma 'java.util.concurrent' w Java ME. – BalusC

4

Dwie anonimowe klasy wewnętrzne, takie jak Thorbjørn Ravn Andersen sugerowany niejasno powyżej, działa. Oto przykładowy kod:

public class OnlineResourceAdapter { 

    public final Runnable typeA; 
    public final Runnable typeB; 

    public OnlineResourceAdapter() { 
     typeA = new Runnable() { 
      public void run() { 
       OnlineResourceAdapter.this.getInformationOfTypeA(); 
      } 
     }; 
     typeB = new Runnable() { 
      public void run() { 
       OnlineResourceAdapter.this.getInformationOfTypeB(); 
       // one can use a non-final typed variable 
       // to store, which then<1> 
      } 
     }; 
    } 

    public static void main(String args[]) { 
     OnlineResourceAdapter x = new OnlineResourceAdapter(); 
     new Thread(x.typeA).start(); // start A 
     new Thread(x.typeB).start(); // start B 
     // <1>can be accessed here. 
    } 

    public void getInformationOfTypeA(){ 
     // get information of type A 
     // return the data or directly store in OnlineResourceAdapter. 
    } 

    public void getInformationOfTypeB(){ 
     //get information of type B 
    } 

} 

Edit: Tak, jesteś zaproponowany sposób jest dobrym sposobem. Możesz nawet uczynić metody statycznymi. Możesz użyć "OnlineResourceAdapter.this." dostęp do innych zmiennych do przechowywania wyników.

+0

co sądzisz o mojej wersji anonimowych lekcji? – hsmit

+0

Powinno działać. Nie jestem pewien, czy dobrze jest pozwolić tej klasie obsługiwać wątki: ponieważ nie można kontrolować tego z innych klas. Jako szybkie rozwiązanie będzie działać, ale nie polecałbym go jako rozwiązania długofalowego. Być może odsłonić interfejs Runnable metodami "getInformationOfTypeARunnable()", który następnie zwraca tylko runnable. Nie zapomnij również o synchronizacji zmiennych (słowo kluczowe "volatile"), próbując uzyskać do nich dostęp z innego wątku. – Pindatjuh

Powiązane problemy