2013-02-08 3 views
2

Je tente d'exécuter un processus asynchrone. Sur la base de cet exemple: http://tomee.apache.org/examples-trunk/async-methods/README.htmljava @Asynchronous Méthodes: pas d'exécution asynchrone

Mais la méthode addWorkflow(Workflow workflow) renverrons seulement lorsque le code dans run(Workflow workflow) est entièrement terminée.

Puis, quand il retourne et result.get(); est appelé, je vais l'exception:

Causée par: java.lang.IllegalStateException: Cet objet ne représente pas un acutal avenir

Toute suggestion que J'ai manqué?

@Singleton 
public class WorkflowProcessor { 

@EJB 
private WorkflowManager workflowManager; 

private final static Logger log = Logger.getLogger(WorkflowProcessor.class.getName()); 



public void runWorkflows(Collection<Workflow> workflows) throws Exception{ 
    final long start = System.nanoTime(); 
    final long numberOfWorkflows = workflows.size(); 
    Collection<Future<Workflow>> asyncWorkflows = new ArrayList<>(); 

    for(Workflow workflow : workflows){ 
     Future<Workflow> w = addWorkflow(workflow); 
     asyncWorkflows.add(w); 
    }  
    log.log(Level.INFO, "workflow jobs added {0}", new Object[]{numberOfWorkflows}); 
    for(Future<Workflow> result : asyncWorkflows){ 
     result.get(); 
    } 

    final long total = TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - start); 
    log.log(Level.INFO, "WorkflowProcessor->runWorkflows {0} workflows completed in:{1}", new Object[]{numberOfWorkflows, total}); 

} 

@Asynchronous 
@Lock(LockType.READ) 
@AccessTimeout(-1) 
private Future<Workflow> addWorkflow(Workflow workflow){ 

    run(workflow); 

    return new AsyncResult<Workflow>(workflow);     
} 


private void run(Workflow workflow){ 
    this.workflowManager.runWorkflow(workflow); 
} 

Répondre

4

Le problème est que Java ne peut pas décorer le pointeur implicite. En d'autres termes, l'annotation @Asynchrone ne sera pas traitée et vous effectuez un appel de méthode ordinaire.

Vous pouvez injecter votre singleton avec une référence à lui-même (appelez cela par exemple "self"), puis appelez self.addWorkflow.

Vous pouvez également envisager d'exécuter votre code asynchrone dans un bean sans état. Vous utilisez un verrou en lecture pour addWorkflow, mais runWorkflow a toujours un verrou en écriture. Je pense que vous avez un verrou mort maintenant: vous maintenez le verrou jusqu'à ce que le travail soit terminé, mais aucun travail ne peut être fait jusqu'à ce que le verrou d'écriture soit libéré.

5

Ainsi, la méthode normale serait d'avoir la méthode @Asynchronous dans un autre bean de la méthode de l'appelant.

@Stateless 
public class ComputationProcessor { 

@Asynchronous 
public Future<Data> performComputation { 
    return new AsyncResult<Data>(null); 
} 
} 

@Stateless 
public class ComputationService { 

@Inject 
private ComputationProcessor mProcessor; 

public void ...() { 
    Future<Data> result = mProcessor.performComputation(); 
    ... 
} 
} 

Comme vous le découvriez, il ne fonctionnera pas si la méthode @Asynchronous est dans le même grain que l'appelant.