3

I want to know if I need to measure time elapsed then Single Threaded Program is good approach or Multithreading Program is a good approach for that.

Below is my single threaded program that is measuring the time of our service-

private static void serviceCall() {

    histogram = new HashMap<Long, Long>();
    keys = histogram.keySet();
    long total = 5;
    long runs = total;

    while (runs > 0) {

        long start_time = System.currentTimeMillis();
        result = restTemplate.getForObject("SOME URL",String.class);
        long difference = (System.currentTimeMillis() - start_time);

        Long count = histogram.get(difference);
        if (count != null) {
            count++;
            histogram.put(Long.valueOf(difference), count);
        } else {
            histogram.put(Long.valueOf(difference), Long.valueOf(1L));
        }
        runs--;
    }

    for (Long key : keys) {
        Long value = histogram.get(key);
        System.out.println("MEASUREMENT " + key + ":" + value);
    }
}

Output I get from this Single Threaded Program is- Total call was 5

MEASUREMENT 163:1
MEASUREMENT 42:3
MEASUREMENT 47:1

which means 1 call came back in 163 ms. 3 calls came back in 42 ms and so on.

And also I did tried using Multithreaded program as well to measure the time elapsed. Meaning hitting the service parallely with few threads and then measuring how much each thread is taking.

Below is the code for that as well-

//create thread pool with given size 
    ExecutorService service = Executors.newFixedThreadPool(10);

// queue some tasks 
for (int i = 0; i < 1 * 5; i++) {
    service.submit(new ThreadTask(i, histogram));
}


public ThreadTask(int id, HashMap<Long, Long> histogram) {
    this.id = id;
    this.hg = histogram;
}


@Override
public void run() {

    long start_time = System.currentTimeMillis();

    result = restTemplate.getForObject("",  String.class);
    long difference = (System.currentTimeMillis() - start_time);

    Long count = hg.get(difference);
    if (count != null) {
        count++;
        hg.put(Long.valueOf(difference), count);
    } else {
        hg.put(Long.valueOf(difference), Long.valueOf(1L));
    }

}

And below is the result I get from the above program-

{176=1, 213=1, 182=1, 136=1, 155=1}

One call came back in 176 ms, and so on

So my question is why Multithreading program is taking a lot more time as compared to above Single threaded program? If there is some loop hole in my Multithreading program, can anyone help me to improve it?

AKIWEB
  • 19,008
  • 67
  • 180
  • 294
  • One thing to worry about is that it doesn't look like `hg` is synchronized. If multiple threads are writing to it, it needs to be. That said, I'm not sure it is the reason for the different timing. – Gray Jan 31 '13 at 19:31
  • Have you run this test a number of times? Does the performance look the same each time? Do you wait after the program starts up and runs for a bit before starting your timing? This may be more about JVM startup and JIT compiler optimizations then your task. – Gray Jan 31 '13 at 19:32
  • Gray, yes hg is not synchronized. And for your other questions, yes I have tried several times as well.. So the only loop hole you are thinking of is hg is not synchronized right? And do you know any better approach to measure the time elapsed that I can follow? – AKIWEB Jan 31 '13 at 19:33
  • 1
    I suspect that a single thread can re-use a connection making following requests faster whereas different threads need to establish a connection each. (You can see that your worst timing is repeated in the multi-threaded example) What is critical is the end to end time. Multiple threads is always going to use more CPU than one, but you might hope that in a longer test the end to end time is better. I would run the test for at least 10 seconds. – Peter Lawrey Jan 31 '13 at 19:36
  • Not sure what a "loop hole" is. I was just saying that you should consider making requests beforehand to warm up the JVM and _then_ start your wall-clock timing tests. But I think that what @digitaljoe is saying is correct. – Gray Jan 31 '13 at 19:38

1 Answers1

3

Your multi-threaded program likely makes all the requests at the same time which puts more strain on the server which will cause it to respond slower to all request.

As an aside, the way you are doing the update isn't threadsafe, so your count will likely be off in the multithreaded scenario given enough trials.

For instance, Thread A and B both return in 100 ms at the same time. The count in histogram for 100 is 3. A gets 3. B gets 3. A updates 3 to 4. B updates 3 to 4. A puts the value 4 in the histogram. B puts the value 4 in the histogram. You've now had 2 threads believe they incremented the count but the count in the histogram only reflects being incremented once.

digitaljoel
  • 26,265
  • 15
  • 89
  • 115
  • So what do you suggest me? I should make a single threaded program to measure the time elapsed? – AKIWEB Jan 31 '13 at 19:35
  • 1
    What's the point of the tests @Nevzz03. To see how many of those requests you can do concurrently? Doing them one at a time will make each request faster but all requests will finish in a slower amount of time. – Gray Jan 31 '13 at 19:39
  • Thanks digitaljoel for the suggestion. Can you suggest me where I need to modify my code to overcome this problem? Any example will make me understand this scenario very well. – AKIWEB Jan 31 '13 at 19:40
  • @Gray, I need to enhance this test, to make around 1000 or 10000 calls to my service concurrently(as this will be the actual behavior in production) and measure the time elapsed. Because in production there will around some millions calls to our service. So that is the reason I was trying to measure the performace of my service. And I was sure that there is something wrong in my Multithreading program for sure. – AKIWEB Jan 31 '13 at 19:42
  • No, I think your timing should work @Nevzz03. Just understand that the performance of your system is going to be more about the concurrent requests then any one request being called 1000 times. You might want to play around with thread-pool sizes and limit the number of concurrent requests to optimize your requests/second. – Gray Jan 31 '13 at 19:45
  • Thanks Gray. But I need to synchronized HashMap right to overcome the problem digitaljoel has mentioned in his answer? If yes, can you guide me with an example what code changes I need to make? – AKIWEB Jan 31 '13 at 20:11
  • @Nevzz03 I would suggest you look at jmeter. It will make the requests for you and give you a graph. It'll fire up multiple threads and hammer your system if that's what you want. If you want to keep your own code, you are going to want a synchronized mechanism to update the histogram. You could extend `ConcurrentHashMap` and provide a synchronized `increment` method that would do the get, increment, and put, or you could provide that method in your own class and pass the key and map into it. In any case, you want a ConcurrentHashMap, but simply changing to ConcurrentHashMap alone isn't enough – digitaljoel Jan 31 '13 at 20:15
  • Thanks digitaljoel for the suggestion. I would for sure try out JMeter in coming days. And regarding your suggestion making it synchonized, can you put together a code as an example basis on my above code that will work in Multithreading scenario. By that way I can understand it much better how to implement synchronized stuff. Thanks in advance. – AKIWEB Jan 31 '13 at 22:57
  • Sorry, I'm not going to write your code. You should read up about synchronization in java, maybe http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html then you should be able to extend `ConcurrentHashMap` and add a simple method called increment that does the get, increment, and put and is synchronized, then use that instead of the map you are currently using. – digitaljoel Jan 31 '13 at 23:19