Anunay Arunav
Anunay Arunav

Reputation: 89

Starting thread in a servlet, what can be the issues?

I have a web application, that, on a single request may require to load hundreds of data. Now the problem is that data is scattered. So, I have to load data from several places, apply filters on them, process them and then respond. Performing all these operations sequentially makes servlet slow!

So I have thought of loading all the data in separate threads like t[i] = new Thread(loadData).start();, waiting for all threads to finish using while(i < count) t[i].join(); and when done, join the data and respond.

Now I am not sure if this approach is right or there is some better method. I have read somewhere is that spawning thread in servlets is not advisable.

My desired code will look something like this.

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException 
{
       Iterable<?> requireddata = requiredData(request);
       Thread[] t = new Thread[requireddata.size];
       int i = 0;
       while (requireddata.hasNext())
       {
             t[i]  = new Thread(new loadData(requiredata.next())).start();
             i++;
       }
       for(i = 0 ; i < t.length ; i++)
         t[i].join();
       // after getting the data process and respond!
}

Upvotes: 1

Views: 5603

Answers (4)

Bikash Rath
Bikash Rath

Reputation: 159

Since you are waiting for all the threads to complete and then you are providing the response, IMO multiple threads won't help if you are using just CPU cycles. It will only increase the response time by adding the context switch delay in the threads. A single thread will be better. However if network/IO etc are involved you can make use of thread pool.

But you would like to re-consider your approach. Processing huge amount of data synchronously in a http request is not advisable. Will not be a good experience for the end user. What you can do is start a thread to process the data and provide a response saying "It is processing". You can provide the web user with some kind gesture to check the status whenever he wants.

Upvotes: 0

Santosh Kumar Pandey
Santosh Kumar Pandey

Reputation: 91

You may consider using Executor framework from java.util.concurrent api. For example you can create your computation task as Callable and then submit that task to a ThreadPoolExecutor. Sample code from Java Concurrency in Practice:-

public class Renderer {
    private final ExecutorService executor;
    Renderer(ExecutorService executor) { this.executor = executor; }

    void renderPage(CharSequence source) {
        final List<ImageInfo> info = scanForImageInfo(source);
        CompletionService<ImageData> completionService =
            new ExecutorCompletionService<ImageData>(executor);
    for (final ImageInfo imageInfo : info)
        completionService.submit(new Callable<ImageData>() {
            public ImageData call() {
                return imageInfo.downloadImage();
                }
               });
renderText(source);
try {
    for (int t = 0, n = info.size(); t < n; t++) {
    Future<ImageData> f = completionService.take();
    ImageData imageData = f.get();
    renderImage(imageData);
    }
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
} catch (ExecutionException e) {
    throw launderThrowable(e.getCause());
}
  }
}

Upvotes: 0

Jiri Kremser
Jiri Kremser

Reputation: 12857

Sounds like a problem for the CyclicBarrier.

For example:

ExecutorService executor = Executors.newFixedThreadPool(requireddata.size);

public void executeAllAndAwaitCompletion(List<? extends T> threads){
   final CyclicBarrier barrier = new CyclicBarrier(threads.size() + 1);
   for(final T thread : threads){
       executor.submit(new Runnable(){
           public void run(){
                //it is not a mistake to call run() here
                thread.run();
                barrier.await();
           }
       }); 
    }
   barrier.await();
}

The last thread from threads will be excuted once the all others finish.

Instead of calling Executors.newFixedThreadPool(requireddata.size);, it is better to reuse some existing thread pool.

Upvotes: 0

JB Nizet
JB Nizet

Reputation: 692231

The main problem is that you'll bring the server to its knees if many concurrent requests comes in for your servlet, because you don't limit the number of threads that can be spawned. Another problem is that you keep creating new threads instead of reusing them, which is inefficient.

These two problems are solved easily by using a thread pool. And Java has native support for them. Read the tutorial.

Also, make sure to shutdown the thread pool when the webapp is shut down, using a ServletContextListener.

Upvotes: 6

Related Questions