2017-10-05 6 views
0

Quand je lance le code suivant:Comment obtenir le comportement MoreExecutors.newDirectExecutorService() en utilisant ThreadPoolExecutor nu?

package foo.trials; 

import com.google.common.util.concurrent.MoreExecutors; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 

import java.util.Random; 
import java.util.concurrent.Callable; 
import java.util.concurrent.ExecutionException; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Future; 
import java.util.concurrent.Semaphore; 
import java.util.concurrent.SynchronousQueue; 
import java.util.concurrent.ThreadPoolExecutor; 
import java.util.concurrent.TimeUnit; 

public class DirectExecutorService { 
    private static final Logger logger_ = LoggerFactory.getLogger(DirectExecutoService.class); 

    public static void main(String[] args) { 
     boolean useGuava = true; 

     final ExecutorService directExecutorService; 
     if (useGuava) { 
      directExecutorService = MoreExecutors.newDirectExecutorService(); 
     } else { 
      directExecutorService = new ThreadPoolExecutor(
        0, 1, 0, TimeUnit.DAYS, 
        new SynchronousQueue<Runnable>(), 
        new ThreadPoolExecutor.CallerRunsPolicy()); 
      directExecutorService.submit(new BlockingCallable()); 
     } 

     Future<Boolean> future = directExecutorService.submit(new MyCallable()); 
     try { 
      logger_.info("Result: {}", future.get()); 
     } catch (InterruptedException e) { 
      logger_.error("Unexpected: Interrupted!", e); 
     } catch (ExecutionException e) { 
      logger_.error("Unexpected: Execution exception!", e); 
     } 
     logger_.info("Exiting..."); 
    } 

    static class MyCallable implements Callable<Boolean> { 
     static final Random _random = new Random(); 
     @Override 
     public Boolean call() throws Exception { 
      logger_.info("In call()"); 
      return _random.nextBoolean(); 
     } 
    } 

    static class BlockingCallable implements Callable<Boolean> { 

     Semaphore semaphore = new Semaphore(0); 
     @Override 
     public Boolean call() throws Exception { 
      semaphore.acquire(); // this will never succeed. 
      return true; 
     } 
    } 
} 

Je reçois la sortie suivante

13:36:55.960 [main] INFO a.t.DirectExecutoService - In call() 
13:36:55.962 [main] INFO a.t.DirectExecutoService - Result: true 
13:36:55.963 [main] INFO a.t.DirectExecutoService - Exiting... 

Notez que tous l'exécution se passe dans le fil main. En particulier, l'appel callable est distribué dans le thread appelant. Bien sûr, c'est ce que l'on peut attendre de MoreExecutors.newDirectExecutorService() pas de surprise là-bas.

Et j'obtiens un résultat similaire lorsque je mets la variable useGuava à false.

13:45:14.264 [main] INFO a.t.DirectExecutoService - In call() 
13:45:14.267 [main] INFO a.t.DirectExecutoService - Result: true 
13:45:14.268 [main] INFO a.t.DirectExecutoService - Exiting... 

Mais si je commente la ligne suivante

directExecutorService.submit(new BlockingCallable()); 

puis-je obtenir la sortie suivante.

13:37:27.355 [pool-1-thread-1] INFO a.t.DirectExecutoService - In call() 
13:37:27.357 [main] INFO a.t.DirectExecutoService - Result: false 
13:37:27.358 [main] INFO a.t.DirectExecutoService - Exiting... 

Comme on peut le voir l'appel du appelable se produit dans un autre thread pool-1-thread-1. Je pense pouvoir expliquer pourquoi cela arrive; peut-être parce que le pool de threads peut avoir (jusqu'à) 1 thread disponible, donc le 1st Callable est envoyé à ce thread supplémentaire qui a été utilisé par BlockingCallable.

Ma question est de savoir comment créer un ExecutorService qui fera quoi DirectExecutorService sans avoir à graver artificiellement un thread avec un callable qui ne finira jamais? Pourquoi je demande cela?

  1. J'ai une base de code qui utilise la goyave à la version 11.0. Je devrais éviter de mettre à jour à 17.0+ - qui offre MoreExecutors.newDirectExecutorService() - si je peux.
  2. ThreadPoolExecutor ne permet pas de définir maxThreads à 0. Il serait étrange que cela le permette, mais si c'était le cas, cela aurait aussi résolu mon problème.
  3. Enfin, je fus surpris de remarquer ce comportement - j'avais supposé (à tort) que l'utilisation CallerRunsPolicy causerait toutes les call de tousCallable s à exécuter dans le fil de l'appelant. Donc, je voulais mettre mon expérience et bidouiller là-bas afin que quelqu'un d'autre puisse sauver les heures qui ont fini par brûler en essayant de comprendre cela. :(

est-il mieux ainsi/plus idiomatiques pour atteindre DirectExecutorService comme comportement si on ne peut pas passer à la goyave 17.0+?

Répondre

2

est-il mieux ainsi/plus idiomatiques pour atteindre DirectExecutorService comme si le comportement on ne peut pas passer à goyave 17.0+?

Si c'est votre seul problème ici, vous devez utiliser MoreExecutors.sameThreadExecutor().Il est essentiellement newDirectExecutorService() avant qu'il ne soit déplacé vers une nouvelle méthode (et directExecutor() a été ajouté), voir Javadoc:

Depuis: 18.0 (présent comme MoreExecutors.sameThreadExecutor() depuis 10,0)

BTW: Vous devriez vraiment mettre à jour à la nouvelle goyave, vous en utilisez presque une de six ans!

+0

Voilà, merci! Point sur la mise à niveau est bien pris. –