2011-08-19 1 views
1

Je suis triyng pour expérimenter la programmation multithread (nouveau pour moi) et j'ai quelques questions. J'utilise un ThreadPoolTaskExecutor avec une TestTask qui implémente Runnable et une méthode run qui dort pendant X secondes. Tout s'est bien passé et tous mes TestTask ont ​​été exécutés dans un fil différent. D'accord. Maintenant, la partie difficile est que je veux connaître le résultat d'une opération effectuée dans le fil. J'ai donc lu des trucs sur Google/stack/etc et j'ai essayé d'utiliser Future. J'utilise la méthode get pour obtenir (oh vraiment?) Le résultat de la méthode call et que la partie fonctionne mais que la tâche de test est exécutée l'une après l'autre (et pas en même temps) comme avant). Donc je devine que je n'ai pas bien compris quelque chose mais je ne sais pas quoi ... et c'est pourquoi j'ai besoin de votre aide!Comment utiliser correctement pool de threads et obtenir un résultat d'un thread?

Le test classe wich lancement:

public void test(String test) { 

    int max = 5; 
    for (int i = 0; i < max; i++) { 
     TestThreadService.launch(i); 
    } 
    System.out.println("END"); 

} 

La classe TestThreadService:

public class TestThreadService { 

private ThreadPoolTaskExecutor taskExecutor; 

public void launch(int i) { 
    System.out.println("ThreadNumber : "+i); 
    taskExecutor.setWaitForTasksToCompleteOnShutdown(false); 
    TestTask testTask = new TestTask(i); 
    FutureTask<Integer> futureOne = new FutureTask<Integer>(testTask); 
    taskExecutor.submit(futureOne); 
    try { 
     Integer result = futureOne.get(); 
     System.out.println("LAUNCH result : "+i+" - "+result); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
    } 

public void setTaskExecutor(ThreadPoolTaskExecutor taskExecutor) { 
    this.taskExecutor = taskExecutor; 
} 

} 

et la classe TestTask:

public class TestTask implements Callable<Integer> { 

public Integer threadNumber; 
private Integer valeur; 

    public TestTask(int i) { 
    this.threadNumber = i; 
    } 

    public void setThreadNumber(Integer threadNumber) { 
    this.threadNumber = threadNumber; 
    } 

    @Override 
    public Integer call() throws Exception { 
     System.out.println("Thread start " + threadNumber); 
     // generate sleeping time 
     Random r = new Random(); 
     valeur = 5000 + r.nextInt(15000 - 5000); 
     System.out.println("Thread pause " + threadNumber + " " + valeur); 
     try { 
      Thread.sleep(valeur); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
     System.out.println("Thread stop" + threadNumber); 
     return this.valeur; 
    } 

} 

Je ne suis pas mauvais en Java mais est la première fois que j'essaie d'utiliser un fil différent, c'est un nouveau pour moi.

Qu'est-ce que je fais de mal?

Merci!

Répondre

1

Dans votre méthode test,

TestThreadService.launch(1); 

devrait probablement

TestThreadService.launch(i); 

La chose principale est que le

Integer result = futureOne.get(); 

appel à la méthode launch. L'appel get() sur une FutureTask est une opération de blocage, ce qui signifie qu'elle ne retournera pas tant que la tâche n'est pas terminée. C'est pourquoi vous voyez un comportement en série. Le cas d'utilisation que vous émulez (l'exécution d'un tas d'activités et l'attente de leur exécution) n'est pas celui pour lequel ThreadPoolTaskExecutor est idéalement adapté. Il n'a pas la fonction "join" que les threads bruts ont. Cela beeing dit, ce que vous voulez faire est quelque chose comme

public Future<Integer> launch(int i) { 
    System.out.println("ThreadNumber : "+i); 
    taskExecutor.setWaitForTasksToCompleteOnShutdown(false); 
    TestTask testTask = new TestTask(i); 
    FutureTask<Integer> futureOne = new FutureTask<Integer>(testTask); 
    return taskExecutor.submit(futureOne); 
    } 

Et dans votre méthode d'essai

public void test(String test) { 
    List<Future<Integer>> tasks = new ArrayList<Future<Integer>>(); 
    int max = 5; 
    for (int i = 0; i < max; i++) { 
     tasks.add(TestThreadService.launch(i)); 
    } 
    for (Future<Integer> task : tasks) { 
     System.out.println("LAUNCH result : " + task.get()); 
    } 
    System.out.println("END"); 

} 
0

vous pouvez également déplacer setWaitForTasksToCompleteOnShutdown (false) dans une autre méthode, car pour ne soyez pas appelé à chaque fois vous lancez un thread, ce qui est, comme je le vois, (pas beaucoup de threads), mais dans un autre scénario, avec plus de tâches: un travail inutile et coûteux.

Vous pouvez également créer une méthode publique sur le service, appelée: configure(); ou, pré-lancement(); avant de commencer à créer des threads.

gluck!

Questions connexes