Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: Run a Callable in a separate process

Given an instance x of Callable<T>, how can I run x in a separate process such that I can redirect the standard input and output of the process? For example, is there a way to build a Process from a Callable? Is there a standard Executor that gives control over input and output?

[UPDATE] It's not important that the Callable execute in a new process as opposed to a new thread. What I want is to put the Callable instance in a "harness", so that I can control its stdin/stdout. AFAIK, this calls for a new process.

like image 670
Chris Conway Avatar asked May 02 '26 10:05

Chris Conway


1 Answers

More generally:

Given an instance x of Callable utilizing global variables A and B, how can I run x concurrently such that x sees custom values for A and B, rather than the "original" values of A and B?

And the best answer is, don't use global variables. Dependency inject things like that. Extend Callable and add methods setStdIn, setStdOut (and setStdErr if you need it).

I know this isn't the answer you're looking for, but the solutions I have seen for this all require a new process, and the only way you are getting that Callable into a new process is to change the code of the Callable so it is serializable, or provides a class name, or some other hack, so instead of making changes that will give you a nasty, brittle solution, just do it right*

* "right" being to use the widely accepted pattern of dependency injection to provide loose coupling. YMMV

UPDATE: In response to comment 1. Here is your new 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);  
}

and your tasks would look like:

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

}

No need for a process. Any solution (even one using processes) is almost certainly going to require code changes to the Callables in some way. This is the simplest (just replace System.out with this.out).

like image 56
noah Avatar answered May 04 '26 01:05

noah



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!