Domanda

Data un'istanza x di Callable<T>, come posso eseguire Process in un processo separato in modo da poter reindirizzare l'input e l'output standard del processo? Ad esempio, c'è un modo per creare un Callable da un Executor? Esiste uno standard <=> che fornisce il controllo su input e output?

[AGGIORNAMENTO] Non è importante che <=> venga eseguito in un nuovo processo anziché in un nuovo thread. Quello che voglio è mettere l'istanza <=> in un & Quot; harness & Quot ;, in modo da poter controllare il suo stdin / stdout. AFAIK, questo richiede un nuovo processo.

È stato utile?

Soluzione

Più in generale:

  

Data un'istanza x di Callable che utilizza le variabili globali A e B, come posso eseguire x contemporaneamente in modo tale che x veda valori personalizzati per A e B, piuttosto che " original " valori di A e B?

E la risposta migliore è, non usare le variabili globali. La dipendenza inietta cose del genere. Estendi Callable e aggiungi i metodi setStdIn, setStdOut (e setStdErr se ne hai bisogno).

So che questa non è la risposta che stai cercando, ma le soluzioni che ho visto per tutto ciò richiedono un nuovo processo e l'unico modo per ottenere che la Callable si trasformi in un nuovo processo è cambiare il codice di il Callable in modo che sia serializzabile, o fornisca un nome di classe o qualche altro hack, quindi invece di apportare modifiche che ti daranno una soluzione sgradevole e fragile, fallo bene *

* " destra " essere quello di utilizzare il modello ampiamente accettato di iniezione di dipendenza per fornire accoppiamento libero. YMMV

AGGIORNAMENTO: in risposta al commento 1. Ecco la tua nuova interfaccia:

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);  
}

e le tue attività sarebbero simili:

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;
    }

}

Non è necessario un processo. Qualsiasi soluzione (anche quella che utilizza processi) richiederà quasi sicuramente modifiche al codice dei Callable in qualche modo. Questo è il più semplice (basta sostituire System.out con this.out).

Altri suggerimenti

stdin / stdout può essere reindirizzato per l'intero sistema, ma non sono sicuro che possa essere reindirizzato per un singolo thread: lo ricevi sempre dal sistema. (Puoi fare in modo che System.out vada su un altro flusso, ma l'ho usato per catturare le tracce dello stack prima che esistesse un metodo per ottenere la traccia come stringa)

Potresti reindirizzare stdin / stdout, eseguire il callable quindi reindirizzarlo indietro, ma se qualcos'altro usa System.out mentre viene reindirizzato, andrà anche al tuo nuovo file.

I metodi sarebbero System.setIn () e System.setOut () (e System.setErr ()) se vuoi seguire quella rotta.

Cerca di strutturare il tuo codice usando la parametrizzazione dall'alto, l'iniezione delle dipendenze o come vuoi chiamarla. Evita la statica, anche quelli vestiti da singoli o nascosti in una cattiva biblioteca.

Se non vuoi rimuovere l'uso di System.in/out/err sei fortunato. Questi possono essere impostati globalmente con System.set(In/Out/Err). Per poter eseguire lo streaming in modo diverso per i singoli thread, impostare un'implementazione che utilizza ThreadLocal per trovare un obiettivo a cui delegare. I locali dei thread sono generalmente malvagi, ma possono essere utili in situazioni sfortunate.

Dai chiarimenti, sembra che il poster originale non abbia bisogno di creare un processo separato.

Dai un'occhiata alla classe ProcessBuilder, ti dà la possibilità di catturare lo stdout e lo stderr del processo che avvia.

È possibile creare una classe Main che esegue un Callable e quindi avviarlo come un altro jvm con un ProcessBuilder. La classe Main può accettare il nome della classe del tuo callable come parametro di input della riga di comando e caricarlo con Class.forName () e Class.newInstance ().

Un'alternativa, se si desidera che esegua una specifica istanza richiamabile, è serializzare l'istanza in un file prima di avviare l'altro processo (sarebbe una forma molto grezza di comunicazione tra i due processi).

La domanda è: perché vuoi farlo? non puoi semplicemente eseguire il tuo callable in un altro thread? java.util.concurrent ha alcuni pool di thread utili, solo per quello.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top