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?
- 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. ThreadPoolExecutor
ne permet pas de définirmaxThreads
à 0. Il serait étrange que cela le permette, mais si c'était le cas, cela aurait aussi résolu mon problème.- Enfin, je fus surpris de remarquer ce comportement - j'avais supposé (à tort) que l'utilisation
CallerRunsPolicy
causerait toutes lescall
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+?
Voilà, merci! Point sur la mise à niveau est bien pris. –