Question

Étant donné une instance x de Callable<T>, comment puis-je exécuter Process dans un processus séparé, de manière à pouvoir rediriger l'entrée et la sortie standard du processus? Par exemple, existe-t-il un moyen de créer un Callable à partir d'un Executor? Existe-t-il une norme <=> permettant de contrôler les entrées et les sorties?

[UPDATE] Il n'est pas important que <=> soit exécuté dans un nouveau processus par opposition à un nouveau thread. Ce que je veux, c’est de placer l’instance <=> dans un & "Harnais &"; Afin que je puisse contrôler son stdin / stdout. À ma connaissance, cela appelle un nouveau processus.

Était-ce utile?

La solution

Plus généralement:

  

Etant donné une instance x de Callable utilisant les variables globales A et B, comment puis-je exécuter x simultanément afin que x voie les valeurs personnalisées pour A et B, plutôt que le & "original &"; valeurs de A et B?

Et la meilleure réponse est de ne pas utiliser de variables globales. La dépendance injecte des choses comme ça. Étendez Callable et ajoutez les méthodes setStdIn, setStdOut (et setStdErr si vous en avez besoin).

Je sais que ce n’est pas la solution que vous cherchez, mais les solutions que j’ai trouvées à cet égard nécessitent toutes un nouveau processus. La seule façon d’introduire ce Callable dans un nouveau processus consiste à modifier le code de Callable pour qu'il soit sérialisable ou donne un nom de classe ou un autre hack, donc au lieu de faire des changements qui vous donneront une solution désagréable et cassante, faites-le comme il convient *

* " right " étant d'utiliser le modèle largement accepté d'injection de dépendance pour fournir un couplage lâche. YMMV

UPDATE: en réponse au commentaire 1. Voici votre nouvelle interface:

import java.io.InputStream;
import java.io.PrintStream;
import java.util.concurrent.Callable;


public interface MyCallable<V> extends Callable<V> {
  void setStdIn(InputStream in);
  void setStdOut(PrintStream out);  
}

et vos tâches ressemblent à:

import java.io.InputStream;
import java.io.PrintStream;


public class CallableTask implements MyCallable<Object> {

    private InputStream in = System.in;
    private PrintStream out = System.out;

    public void setStdIn(InputStream in) {
        this.in = in;
    }

    public void setStdOut(PrintStream out) {
        this.out = out;
    }

    public Object call() throws Exception {
        out.write(in.read());
        return null;
    }

}

Pas besoin de processus. Toute solution (même celle utilisant des processus) nécessitera presque certainement des modifications de code dans les Callables. C’est le plus simple (il suffit de remplacer System.out par this.out).

Autres conseils

stdin / stdout peut être redirigé pour tout le système, mais je ne suis pas sûr qu'il puisse être redirigé pour un seul thread - vous l'obtenez toujours à partir de System. (Vous pouvez cependant faire passer System.out dans un autre flux. Je l'ai utilisé pour récupérer les traces de pile avant qu'il y ait une méthode pour obtenir la trace sous forme de chaîne).

Vous pouvez rediriger stdin / stdout, exécuter le callable puis le rediriger, mais si quelque chose d'autre utilise System.out pendant qu'il est redirigé, cela ira également dans votre nouveau fichier.

Les méthodes seraient System.setIn () et System.setOut () (et System.setErr ()) si vous souhaitez suivre cette voie.

Efforcez-vous de structurer votre code à l'aide du paramétrage à partir de, de l'injection de dépendance ou de la méthode que vous souhaitez appeler. Évitez la statique, même ceux habillés en singletons ou cachés dans une mauvaise bibliothèque.

Si vous ne souhaitez pas supprimer l'utilisation de System.in/out/err, vous avez de la chance. Ceux-ci peuvent être définis globalement avec System.set(In/Out/Err). Pour pouvoir diffuser en continu différemment pour des threads individuels, définissez une implémentation qui utilise ThreadLocal pour rechercher une cible à déléguer. Les fils de discussion sont généralement diaboliques, mais peuvent être utiles dans des situations malheureuses.

D'après les clarifications, il semble que l'affiche originale n'a pas besoin de créer un processus séparé.

Examinez la classe ProcessBuilder, elle vous offre la possibilité de capturer les sorties stdout et stderr du processus lancé.

Vous pouvez créer une classe Main qui exécute Callable, puis la lancer sous un autre jvm avec ProcessBuilder. La classe Main peut accepter le nom de classe de votre appelable comme paramètre d'entrée de ligne de commande et le charger avec Class.forName () et Class.newInstance ().

Une autre solution, si vous souhaitez exécuter une instance appelable spécifique, consiste à sérialiser l’instance sur un fichier avant de lancer l’autre processus (ce serait une forme très grossière de communication entre les deux processus).

La question est, pourquoi voulez-vous le faire? ne pouvez-vous pas simplement lancer votre appelable dans un autre thread? java.util.concurrent a quelques pools de threads utiles, rien que pour cela.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top