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).