Q:

Running multiple instances of thread class to read multiple files

So i have a callable class which processes a given text file then produces an output text file. I want to process each file with its own thread however I am confused about the difference in starting a thread with the same object vs starting a thread with a different thread object. Both threads do exact same thing except the input file is different. Initially I wanted to use one thread object but then how would I load different files if im using one thread object.
For instance
    ExecutorService pool = Executors.newFixedThreadPool(2);

    Runner test = new Runner("file1.txt");

    Future<String> ret = pool.submit(test);

    Future<String> ret2 = pool.submit(test);

VS
    ExecutorService pool = Executors.newFixedThreadPool(2);

    Runner test = new Runner("file1.txt");

    Runner test2 = new Runner("file2.txt");

    Future<String> ret = pool.submit(test);

    Future<String> ret2 = pool.submit(test2);

My Questions/Factors

The above example clearly names the textfiles where as in the actual implementation the files are not known hence accessed through iterating a loop.
If i were to use a single thread object then how would I process different files
If two two separate thread objects are used then would I still need to worry about   synchronization.

Thanks in advance

A:

Both ways are possible: You can use a different object per task, you can share objects, and you can also mix the two approaches. In most cases, the simplest solution is to create an object per task. That's also true for your example. With a loop, I might look as follows:
List<Future<String>> futures = new ArrayList<>();
for (String pathname : pathnames) {
    futures.add(pool.submit(new Runner(pathname));
}
for (Future<String> future : futures) {
    ...
}

It's also possible to share an object. However, that's a bit more complicated.
class Worker implements Callable<String> {
    private final List<String> pathnames;
    private final AtomicInteger index = new AtomicInteger();
    public Worker(List<String> pathnames) {
        this.pathnames = pathnames;
    }
    public String call() {
        String pathname = list.get(index.getAndIncrement());
        ...
        return ...;
    }
}

// caller
Worker worker = new Worker(pathnames);
List<Future<String>> futures = new ArrayList<>();
for (String pathname : pathnames) {
    futures.add(pool.submit(worker));
}

As you can see, the worker has to fetch the pathname, instead of passing the pathname to the worker, because the latter isn't directly possible with the executor framework. There is also some need for synchronization.

