views:

191

answers:

7
class ApplicationContext{
    private final NetworkObject networkObject = new networkObject();

    public ApplicationContext(){
      networkObject.setHost("host");
      networkObject.setParams("param");
    }

    public searchObjects(ObjectType objType){
        networkObject.doSearch(buildQuery(objType));
    }
}

class NetworkObject{
    private final SearchObject searchObject = new SearchObject();

    public doSearch(SearchQuery searchQuery){
        searchObject.search(searchQuery); //threadsafe, takes 15(s) to return
    }
}

Consider a webserver running a web application which creates only one ApplicationContext instance (singleton) and uses the same applicationInstance to call searchObjects e.g.

 ApplicationContext appInstance = 
                  ApplicationContextFactory.Instance(); //singleton

Every new request to a webpage say 'search.jsp' makes a call

 appInstance.searchObjects(objectType);

I am making 1000 requests to 'search.jsp' page. All the threads are using the same ApplicationContext instance, and searchObject.search() method takes 15 seconds to return. My Question is Do all other threads wait for their turn (15 sec) to execute when one is already executing the searchObject.search() function or All threads will execute searchObject.search() concurrently, Why??

I hope I have made my question very clear??

Update: Thanks all for clarifying my doubt. Here is my second Question, what difference in performance should be observe when I do:

public synchronized doSearch(SearchQuery searchQuery){
    searchObject.search(searchQuery); //threadsafe, takes 15(s) to return
}

OR

public doSearch(SearchQuery searchQuery){
    searchObject.search(searchQuery); //threadsafe, takes 15(s) to return
}

I believe using the function 'doSearch' without synchronized keyword should be giving more performance. But, when I tested it today, the results came out the other way. The performance was similar or sometimes better when I use synchronized keyword.

Can anyone explain the behavior. How should I debug such cases.

Regards,

Perry

+5  A: 

Well you haven't specified any synchronization in the code, so without any other evidence I'd suspect that all the threads will run concurrently. If SearchObject.search contains some synchronization though, that would obvious limit the concurrency.

Mind you, your JSP container is probably using a thread pool to service the 1000 requests, rather than creating 1000 threads.

EDIT: As for why it may be faster with synchronized: sometimes concurrency isn't actually helpful to throughput. Things like context switching, disk bottlenecks, cache misses etc have that effect. It's usually not a good idea to have more running threads than cores.

For a real-life example, suppose you have a thousand shoppers who all want to buy things from a fairly small shop. How would you go about it? Put all 1000 in the shop at the same time, or keep it down to a fairly small number in the shop at any one time, and a queue outside?

Jon Skeet
please see my Update above!
Devil Jin
A: 

In your case, they will all execute concurrently.

If you wanted to prevent this, you would need to have some kind of synchronization in place to prevent that (e.g. declaring the method as synchronized or using locks).

ETA:

If you declare the doSearch() method as synchronized, only one thread at a time will be able to call it. Other threads will block until the first thread finishes and the waiting threads will be "let in" one at a time. As you can imagine, this will kill your performance if you have lots of threads calling that function.

Eric Petroelje
please see my Update above!
Devil Jin
A: 

If you've got no synchronisation, then each thread will run concurrently and not block on locks.

Note that

// threadsafe

(as commented) means it'll work properly with multiple threads accessing it - not that it'll block threads.

Brian Agnew
please see my Update above!
Devil Jin
A: 

They can all execute it at the same time unless it is declared as synchronized,regardless of the fact that your class is a singleton IIRC.

please see my Update above!
Devil Jin
A: 

If SearchObject.search is synchronized, then yes. Otherwise, just try it and see.

Apocalisp
please see my Update above!
Devil Jin
A: 

Why does it take 15 seconds? If it's waiting for disk access and you only have one disk, then no matter how many threads you have you're limited by the disk seek speed. More threads may even be slower in this situation.

pjc50
I agree that if all threads are waiting for a disk access the performance will be slower. I want to know how will synchronized affect the performance here, supposing the search() method takes a very small time to return
Devil Jin
+1  A: 

It is wise to realise that performance is with respect to a given environment. In this case, it probably is the performance of the software on your laptop or test server. It is wise to check performance on something similar to a production environment before even considering to optimize the code because the bottleneck there could be quite different than on the development machine.

As an example; when I test my software with a large database on my laptop I always end up being harddisk-IO bound. In production however the database server has plenty memory and speedy disks so it would not be wise to optimise my software for IO.

Similar with threading; the processor in my laptop can run one or two processes simultaneously. Having 8 threads does not speed things up. The production machine however might very well be able to handle 8 threads simultaneously.

What I think is more important than performance is semantics. Using a keyword like synchronous is not only instructive to the compiler, but also to the (next) developer.

By using synchronous you share a lock with all other synchronous methods on ApplicationContext, also the methods which might have nothing to do with searchObject. Personally I doubt very much you wish to synchronize on an object called ApplicationContext.

If searchObject were not thread safe I would probably recommend a locking object. This comes in to flavors:

public void doSearch(SearchQuery searchQuery){
   synchronized(searchObject) {// Only if searchObject is guaranteed to be null
       searchObject.search(searchQuery); //threadsafe, takes 15(s) to return
  }
}

or

public class ApplicationContext {
    private SearchObject searchObject = null;
    private final Object searchObjectLock = new Object();    

    public void doSearch(SearchQuery searchQuery){
       synchronized(searchObjectLock) {
           searchObject.search(searchQuery); //threadsafe, takes 15(s) to return
      }
    }
}

Don't forget to lock every use of searchObject to prevent threading trouble. Using this fine-grained locking mechanism you can at least keep the ApplicationContext available to classes which do not need searchObject related functionality.

In your case I would not use any synchronisation as it is not required, and check on production-like hardware before determining bottlenecks.

And if searchObject uses a database make sure the database is property indexed and uses that index. If it needs to do 1000 full table scans it won't be fast anyhow...

extraneon
I agree that Performance is something which is tuned with the hardware. But as general rules or principles we do follow certain guidelines. I agree with Jon about having number of threads equal to number of cores
Devil Jin
yeah, but it's the number of cores on the production system, and not the developer system, which should be the basis of the performance analysis.
extraneon