2010-01-17 34 views
6

Los subprocesos a menudo se diseñan de dos maneras (see java tutorials): extendiendo la clase Thread o implementando la clase Runnable. De cualquier manera, debe especificar qué se ejecutará dentro del hilo.¿Cómo lidiar con múltiples hilos en una clase?

Diseñé una clase, un adaptador para un recurso en línea, que recupera diferentes tipos de información. Esta clase consta de métodos como getInformationOfTypeA() y getInformationOfTypeB(). Ambos contienen código para conectarse a recursos en línea, por lo que ambos deben enhebrarse para evitar interbloqueos.

La pregunta es: ¿cómo debería diseñar esto? Puedo hacerlo como abajo, pero entonces sólo puedo poner en práctica un método:

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 
    } 

} 

Otra forma sería mediante la creación de clases separadas para cada método, pero que parece poco natural para mí.

BTW: Estoy desarrollando mi solicitud en J2ME

ACTUALIZACIÓN:

Gracias a sus respuestas creo que es más satisfaciendo a usar algo como lo siguiente: como métodos

¿Qué opinas de esto:

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 ¿piensas en esto?

Respuesta

1

Para cada clase crea una clase anónima basada en Runnable. Esto le permitirá hacer lo que necesita hacer dentro del método run().

6

Me parece que en realidad debería tener dos clases diferentes: InformationOfTypeAFetcher y InformationOfTypeBFetcher, cada una de las cuales debe implementar Runnable. Cada uno de ellos puede tener una referencia a una instancia de su OnlineResourceAdapter (o algo similar) pero si están haciendo cosas diferentes, deberían ser de clases diferentes.

1

No veo por qué no te gusta la idea de crear múltiples clases, considerando que Java no admite funciones de orden superior y la parte modificable de tu código es el algoritmo.

Pero si quería una sola aplicación de OnlineResourceAdapter podría utilizar el patrón de Estrategia y hacer algo como esto:

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(); 
    } 
} 

y luego, por supuesto, se crearía la mayor cantidad de implementaciones de InformationGetter medida que sea necesario.

Ahora que lo pienso, mirando hacia atrás sobre este enfoque, OnlineResourceAdapter ahora realmente no agrega nada excepto hacer InformationGetter ejecutable. Entonces, a menos que tenga alguna razón convincente para no hacerlo, yo diría que solo tiene InformationGetter implemente Runnable directamente.

+0

danben se hace eco de mi opinión. El patrón de estrategia es una cosa que tal vez quiera ver. Tener clases separadas parece una forma limpia para mí en este caso – Aadith

1

Muchas personas ya han sugerido buenos métodos de cómo hacerlo utilizando varias clases.Ya que parece preferir una manera que no requiere de varias clases, es posible que también desee considerar el uso del constructor para dar información acerca de qué recurso para ir a buscar:

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 
    } 
} 

Uso:

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

A menos que realmente, realmente no debes hacer esto. Cuanto más puedas poner en tipeo estático, mejor. En otras palabras, tenga dos clases separadas. –

+0

Por otro lado, si tiene potencialmente miles de tipos de información para recuperar, o el tipo de información para recibir es un parámetro que el usuario ingresa, este método tendría mucho más sentido para tener el tipo como parámetro constuctor que creando una nueva clase para cada tipo. Sin saber más sobre las necesidades del afiche, es difícil decir cuál es la mejor solución. –

-1

Uso las clases anónimas de tipo Callable (que, a diferencia de Runnable, pueden devolver valores) y ejecutarlas usando Executor. Si la lógica para recuperar información A e información B es muy similar, puede, por supuesto, refactorizar eso y usar una sola, parametriza la clase interna de Callables.

No estoy seguro si Callable y Executor son parte de la especificación J2ME. En Java estándar, me gustaría un enfoque Proxy de todos modos y encapsular el recurso externo como interfaz.

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

Desafortunadamente, no hay 'java.util.concurrent' en Java ME. – BalusC

4

Dos clases internas anónimas, como Thorbjørn Ravn Andersen sugeridas vagamente arriba, funciona. Aquí está un ejemplo de código:

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 
    } 

} 

Editar: manera Sí, estás propuesto es una buena manera. Incluso puedes hacer que los métodos sean estáticos. Puede usar "OnlineResourceAdapter.this". para acceder a otras variables para almacenar los resultados en.

+0

¿qué opinas de mi versión de clases anónimas? – hsmit

+0

Debería funcionar. No estoy seguro de si es bueno dejar que esta clase maneje el subprocesamiento: ya que no puedes controlarlo desde otras clases, entonces. Como solución rápida, funcionaría, pero no lo recomendaría como una solución a largo plazo. Quizás exponer la interfaz de Runnable mediante los métodos "getInformationOfTypeARunnable()", que luego solo devuelve un elemento ejecutable. Además, no olvide sincronizar las variables (palabra clave "volátil") cuando intente acceder a ellas desde otro hilo. – Pindatjuh

Cuestiones relacionadas