0

There are several questions, like here or here, asking why extra threads decrease performance. I get those.

I have a somewhat opposite question: how can just one extra thread increase performance by a factor of e.g. 10 or even 20?

Example code:

           public class MainThreaded {

    public static void main(String[] 

        String filePath = "my\\path\\";

        String[] inFiles = {filePath+"file1.txt",filePath+"file2.txt"};
        String[] outFiles = {filePath + "file1Out.txt", filePath + "file2Out.txt"};

        long startTime = System.currentTimeMillis();

            for (int i = 0; i < inFiles.length; i++) {

                Adder adder = new Adder(inFiles[i], outFiles[i]);
//              adder.doAdd();
                Thread thread = new Thread(adder);
                thread.start();
            }

        long endTime   = System.currentTimeMillis();
        long totalTime = endTime - startTime;
        System.out.println("That took " + totalTime+ " milliseconds");


    }

}



public class MainNoThread {

    public static void main(String[] args) {


        String filePath = "my\\path\\";    
        String[] inFiles = {filePath+"file1.txt",filePath+"file2.txt"};
        String[] outFiles = {filePath + "file1Out.txt", filePath + "file2Out.txt"};

        long startTime = System.currentTimeMillis();

            for (int i = 0; i < inFiles.length; i++) {

                Adder adder = new Adder(inFiles[i], outFiles[i]);
                try {
                    adder.doAdd();
                } catch (IOException e) {
                    e.printStackTrace();
                }

            }

        long endTime   = System.currentTimeMillis();
        long totalTime = endTime - startTime;
        System.out.println("That took " + totalTime+ " milliseconds");

    }

}

public class Adder implements Runnable {

    private String inFile, outFile;

    public Adder(String inFile, String outFile){
        this.inFile = inFile;
        this.outFile = outFile;

    }

    public void doAdd() throws IOException{

        int lines = 0;

        try(BufferedReader reader = Files.newBufferedReader(Paths.get(inFile))){
            while (reader.readLine() != null) {
                lines++;
            }
            try(BufferedWriter writer = Files.newBufferedWriter(Paths.get(outFile))){
                writer.write("Total: " + lines);
            }
        }

    }

    @Override
    public void run() {

        try {
            doAdd();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}
  • 1st app without threads takes ca. 40 milliseconds
  • 2nd version, that creates just one extra new Thread() takes 2 milliseconds.

So my question: what is the reason behind such drastic improvement?

Community
  • 1
  • 1
Andrejs
  • 10,803
  • 4
  • 43
  • 48
  • Are you sure you wait for the thread to finish? Can you show the code? – Justas Mar 21 '17 at 17:47
  • 1
    Did you take disk caching into account? – selbie Mar 21 '17 at 17:48
  • 1
    How did you implement the second version? Without seeing both codes, it is hard to tell what happens. Perhaps you run single threaded first, and when second one runs, files are already in the system`s filesystem cache? – Axel Mar 21 '17 at 17:49
  • No, not sure at all :). But the lines get counted in both files correctly (13k for one file, 5k for the other, approximately) – Andrejs Mar 21 '17 at 17:49
  • 1
    Botched benchmarks can give all sorts of weird results. – Kayaman Mar 21 '17 at 17:49
  • Added full code – Andrejs Mar 21 '17 at 17:52
  • 2
    @Andrey, but in your full code, you just start threads, you don't measure the time it takes to perform the actual work in doAdd(). Or rather, you don't wait for any of your threads to finish, you just start them and then print out how long it took to start the threads. – nos Mar 21 '17 at 17:54
  • @nos Well, the program doesn't exit until all non-daemon threads have finished, but yes, he's displaying "the time it took" before the the threads have finished doing the work. – Kayaman Mar 21 '17 at 17:59

1 Answers1

1

When you call thread.start(), your code does not wait for the thread to finish doing its work before moving on. start() is what is known as a "non-blocking" or "asynchronous" method.

In order to time this accurately, you need to somehow wait for the threads to finish before measuring the time taken. One way to do this is to keep track of all of the threads you create, and then call "thread.join()" for each of them at the end, after kicking them all off. Thread.join() will block (wait) for a thread to finish before continuing.

CAW
  • 369
  • 1
  • 8