0

I have created the below application to test the ExecutorService . I have one Reader thread which reads from a file. The string read(upto 2 lines) is passed recurrently to a writer task which is responsible for printing the string onto the console. I submit this task to an executor pool where the worker threads execute the task. How do I check whether this method is indeed faster as compared to using say only one thread/one process doing the reading and writing both by itself?

public class ClientTest {

ExecutorService e= Executors.newFixedThreadPool(2);
static ClientTest c = new ClientTest();
public static void main(String args[])
{

    Thread reader=new Thread() {
        public void run() {
            BufferedReader br=null;
            int n=0;

            try {
                br = new BufferedReader(new FileReader("C:\\Users\\JOHHNY\\Desktop\\Sample.txt"));


                StringBuilder sb = new StringBuilder();
                String line = br.readLine();

                while (line != null) {
                    sb.append(line);
                    sb.append("\n");
                    n++;
                    if(n%2==0) {
                        c.write(sb);
                        Thread.sleep(1000);
                        sb.setLength(0);

                    }
                    line = br.readLine();
                }

            } 
            catch (Exception e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
           finally {
                try {
                    br.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }


        }



    };
    reader.start();



}

private void write(final StringBuilder sb) {
    e.execute(new Runnable() {
        public void run() {
            System.out.println(Thread.currentThread().getName()+"     "+sb.toString());

        }

    });


}

}

ghostrider
  • 2,046
  • 3
  • 23
  • 46
  • The simplest thing you can try is to invoke `System.nanotime()` before and after performing the task and computing the difference. For real applications, the results of this are probably not good enough, however - measuring Java performance is tricky because the JVM can optimize hot spots in code at runtime. There are lots of tools around this topic - see https://stackoverflow.com/questions/948549/open-source-java-profilers – Hulk Jan 15 '19 at 13:41
  • 3
    Why are you expecting it to be *faster*? The ExecutorService will just enable you to do more things in parallel. It won't speed up any I/O. – jbx Jan 15 '19 at 13:43
  • Yep, furthermore the reader is already using a `BufferedReader` so I/O batching optimisations are already taking place. So probably the bottleneck is actually the `System.out`, which is anyway delivering the result. – jbx Jan 15 '19 at 13:50
  • @jbx So in which scenarios can I expect a faster behaviour with respect to single and mutlithreaded applications? Can you please give an example?What if I persist the data in database instead of just printing it? Would that make a difference in terms of realizing the benefits of multi threading? – ghostrider Jan 15 '19 at 13:57
  • 1
    @ghostrider probably not when persisting to DB. Multithreading helps with CPU-bound operations, i.e. expensive calculations. And it helps when you can perform other operations while waiting for soemthing else to complete. But you also have to take into account that splitting your task into threads and combining the results afterwards does not come for free - it has a certain overhead – Hulk Jan 15 '19 at 14:01
  • 1
    Related: https://stackoverflow.com/questions/15292626/does-multi-threading-improve-performance-how – Hulk Jan 15 '19 at 14:06
  • 1
    If you have 2 or more tasks which are computationally expensive, and do not depend on each other, that is where you will gain benefit from concurrency. You have to be careful that the overheads of managing multiple threads isn't actually makings things worse. Note that to really squeeze out performance, you might also want to look at NIO Channels. You can create a `Pipe` between the `FileChannel` and the `System.out`, or do `transferTo()` directly. If you wanted to process each line, you might want to look at `Files.lines()` to `Stream` the lines, and parallelize their processing. – jbx Jan 15 '19 at 14:08
  • @Hulk, Thanks!! As mentioned by jbx executors are efficient for doing tasks parallely..So on that line what if I modify the application in which while printing the previous string read to console, I can paralelly read next string into the buffer? That can make the application show some parallelism right? – ghostrider Jan 15 '19 at 14:10
  • 1
    In theory, you could get a little bit of concurrency. But it won't be much, because the reading is buffered anyway, and the writing is synchronized. IO is one of the examples where you typically don't gain much by multithreading. Networking is different - you can perhaps send out multiple requests to multiple servers and do some other processing while waiting for the responses. – Hulk Jan 15 '19 at 14:19
  • 1
    Another example where it can help is UI - you can have one thread that is responsible for performing the actual work, and another one just waiting for user input, so that the UI feels responsive. – Hulk Jan 15 '19 at 14:29
  • @Hulk, Can you elaborate more on "Reading is buffered anyway and writing is synchronized"? Does it mean i can write simultaneously to the console? – ghostrider Jan 15 '19 at 14:30
  • 1
    What I mean by "buffered" (and jbx already mentioned, too) is that [`BufferedReader`](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/io/BufferedReader.html) does not read the lines from the file one-by-one. Instead, it reads a junk of bytes (the size can be specified via the constructor at once). Reading the next line just reads from this buffer (in memory), which is extremely fast anyway. – Hulk Jan 15 '19 at 14:35
  • 1
    And by "synchronized", I mean that `PrintStream` uses actual `synchronized(this){}`-blocks in all implementations that I know of. This means that when multiple Threads invoke `println()` concurrently, the lines may be in arbitrary order, but the characters of each line will be printed correctly one after the other, without any chance for characters from other threads appearing in between them. It also means that at any given time, only one thread can write, while all the others are blocked until that thread has completed printing its line. – Hulk Jan 15 '19 at 14:42
  • 1
    Note that this behavior of `PrintStream` is not strictly guaranteed anywhere, but it has been that way for a very long time. While it is unwise to rely on it, it is good to keep in mind when considering its performance - see https://stackoverflow.com/questions/9459657/is-multi-thread-output-from-system-out-println-interleaved – Hulk Jan 15 '19 at 14:52

0 Answers0