Why should I avoid using InheritableThreadLocal in servlets? - java

I am using InheritableThreadLocal in my Servlet Class. So that It will available from it's child threads. Is that evil using InheritableThreadLocal in thread pool executors? . Such as servlet thread pool.
My Questions.
1) Why should we avoid using InheritableThreadLocals in servlets?
2) Is this memory leak possible in InheritableThreadLocal?
3) Is there any alternative for InheritableThreadLocal?.
4) What happens if the thread will be reused , the value stored in threadlocal will not be cleared?
My Real Time Scenario
public class UserAccessFilter implements javax.servlet.Filter {
static final InheritableThreadLocal<String> currentRequestURI = new InheritableThreadLocal<String>();
public void doFilter(ServletRequest req, ServletResponse resp , FilterChain fc) throws IOException, ServletException{
String uri = request.getRequestURI();
fc.doFilter(request, response);
}
}
public class MailServlet extends HttpServlet{
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String mailCount = req.getParameter("mailCount");
if(mailCount != null && !"".equals(mailCount) && mailCount.matches("[0-9]+")){
MailThread mailThread = new MailThread("xxx#gmail.com", generateToAddress(Integer.parseInt(mailCount))); //NO I18N
Thread t = new Thread(mailThread);
t.start();
}
resp.getWriter().println("Mail Servlet.............."); //NO I18N
}
}
class MailThread implements Runnable{
private String from;
private String to;
public MailThread(String from , String to){
this.from = from;
this.to = to;
}
#Override
public void run() {
sendMail();
}
public void sendMail(){
//I want this uri from child threads. I can't pass this value to this constructor.
String uri = currentRequestURI.get();
//Do Mail Operations
}
}
Filter --> Servlet A --> Child Thread ---> Mail Thread (Here I am getting the value setted in filter) .

Why should we avoid using InheritableThreadLocals in servlets?
They represent a potential path for leaking information from one request to another. The "problem" is that requests are handled by a pool of threads. When on request is completed, the next request that a thread handles is likely to be for a different user. But if you forget to clear the thread local state on finishing the first request, there is a potential that it might be used by the second one.
Is a memory leak possible in InheritableThreadLocal?
Yes ... sort of. If we assume that the worker pool is bounded, the thread local state of any thread is likely to be overwritten, clearing the memory leak. At worst the problem is a bounded memory leak ... bounded by the number of threads in the pool.
The information leakage problem is more concerning.
Is there any alternative for InheritableThreadLocal?
Setting attributes in the request or response object is better.
What happens if the thread will be reused, the value stored in threadlocal will not be cleared.
It won't be cleared. THAT is the problem!

Your example works, the MailThread inherits the value of currentRequestURI when it is created.
But the UserAccessFilter and the java.lang.InheritableThreadLocal just serve to confuse what the code is trying to do, which is the evil part.
What's wrong changing the constructor of MailThread so that you can pass the request URI from the MailServlet like this:
MailThread mailThread = new MailThread("xxx#gmail.com", generateToAddress(Integer.parseInt(mailCount)), req.getRequestURI());
Then you have no need for a thread local, you don't need the filter and the code is clearer.

Related

JSP - How to first forward to a view, and then continue processing method in background?

I would like to first forward to the view "/WEB-INF/views/searchResult.jsp" and then process Calculator.lookUp(Type, Place) in the background.
Currently Calculator.lookUp(Type, Place) is processed first, and only once this method is finished is the user forwarded to "/WEB-INF/views/searchResult.jsp".
Thanks for the help!
#WebServlet(urlPatterns="/search.do")
public class SrchServlet extends HttpServlet{
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
String Type = request.getParameter("Type");
String Place = request.getParameter("Place");
request.setAttribute("Type", Type);
request.setAttribute("Place", Place);
//I want the forward to searchResult.jsp to occur
request.getRequestDispatcher("/WEB-INF/views/searchResult.jsp").forward(
request, response);
//and then in backend for the below method to run
Calculator.lookUp(Type, Place);
}
}
Some remarks if you do not like async requests. First, a forward is definitive: you give the hand to the other servlet and next instruction (if any) will never be executed. You need to include the JSP if you want to proceed in sequence. And a trick allows to cause the response to be sent to the client immediately while allowing processing in the servlet: just close the response output writer or stream.
Your code could simply become:
//I want the include searchResult.jsp
request.getRequestDispatcher("/WEB-INF/views/searchResult.jsp").include(
request, response);
// cause the response to be sent to the client
try {
response.getOutputStream().close(); // if the OutputStream was used
}
catch(IllegalStateException e) {
response.getWriter().close(); // if the Writer was used
}
//and then in backend for the below method to run
Calculator.lookUp(Type, Place);
}
I could never find whether this was explicitely allowed per servlet specification, by I can confirm that Tomcat supports it.
No need for any #Asinc...
Try using below code to make your method async but the Type and Place (just in point variable names should start with small letters) both variable should be final:
Runnable task = new Runnable() {
#Override
public void run() {
try {
Calculator.lookUp(Type, Place);// here Place and Type both variable should be final
} catch (Exception ex) {
// handle error which cannot be thrown back
}
}
};
new Thread(task, "ServiceThread").start();
As of I know the below is the better way to solve your problem.
Declare the logic which you need to execute as part of background process in an asynchronous method by declaring the method as,
#Asynchronous / #Async
Remember, Asynchronous method will not return anything that mean return type is void. If you need to return some values, you can return Future. Read more about Asynchronous process.

Multithreading inside Tomcat - Create a Thread Pool

I have a servlet which is used for a long process which takes minutes to complete. Upon receiving a request to this servlet, the long process is executed inside a thread in order to send the response back to the client immediately due to timeout issues:
public class TestServlet extends HttpServlet {
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
//Thread safe code
Thread thread = new Thread() {
public void run() {
try {
Thread.sleep(10000); //simulate long processing
} catch(InterruptedException v) {
}
}
};
thread.start();
}
}
This means that every time I receive a request, a new thread is created. In order not to run into the risk of attacks, I need to control how many threads are allowed. This means having a pool in the context, and implementing a fail-fast if all threads are busy.
I was looking at the Executor interface. My question is, how can I implement this Thread Pool Executor to be accessible from all the requests received and act as a queue for all the threads? Should I declare the executor as a local non-thread safe variable in the servlet to be accessible by all instances of this servlet as shown below?
public class TestServlet extends HttpServlet {
//non-thread safe variables
//declare executor here
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
//instantiate executor in case it is null
Thread thread = new Thread() {
public void run() {
try {
Thread.sleep(10000); //simulate long processing
} catch(InterruptedException v) {
}
}
};
//add thread to the executor
}
}
Or is it possible to declare this executor at context level?
I was looking also at the Tomcat Executor, which I believe is used by Tomcat itself to manage its thread. Would it be possible to also add these threads to this executor as well?
Usually doing explicit thread management in an app server is a bad idea. You could set up the servlet to run in a new thread itself, and thus avoid farming things out to another thread inside the servlet. I haven't looked up whether Tomcat lets you configure the maximum number of simultaneous instances of a servlet allowed, so that might remain an issue.
If you do explicitly use 'Thread.sleep()', don't abandon the 'InterruptedException' like that. It's the wrong thing to do. Look up the right thing (handle and re-interrupt).

Request blocking in doPost() of a HttpServlet

I defined a servlet(map it to /index) and rewrite the doPost method like this :
private Object lock = new Object();
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
System.out.println("start");
synchronized(lock) {
try {
lock.wait(15000);
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.notifyAll();
}
}
when the first request comes in, it prints 'start' then waits at lock.wait(15000);
then the second request comes, and it should be blocked at synchronized(lock); as i thought. But the fact is the second request is blocked out of the doPost method. After the first request goes lock.notifyAll(); then the second request comes into doPost method and prints 'start'.
I found this only happens when two requests query the exactly same url. Is this the way that Tomcat handles for multi-thread ?? I am so confused..
Only the doPost and doGet method of the servlet are thread safe, means for each thread they are invoked independently. The class itself is instantiated only once.
In the code above you are acquiring lock on class variable which will be shared across all request, hence you are getting that locked per request.
To get your expected behaviour move your 'Objectinstantiation insidedoPost` method.

AsyncHttpClient (Java) onComplete(): Does onCompleted() run on the separate thread?

Looking at the code block in the Java library AsyncHttpClient, the client starts a new thread (a Future) to make the request. Will the callback happen on the same thread, or will it run on the "main" thread (in this case, the thread where new AsyncHttpClient() was called?
import com.ning.http.client.*;
import java.util.concurrent.Future;
AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
asyncHttpClient.prepareGet("http://www.ning.com/ ").execute(new AsyncCompletionHandler<Response>(){
#Override
public Response onCompleted(Response response) throws Exception{
// Do something with the Response
// ...
return response;
}
#Override
public void onThrowable(Throwable t){
// Something wrong happened.
}
});
the client starts a new thread (a Future) to make the request.
Nope. The Future basically means: this method already returned but it didn't yet finished processing. The processing will continue in background (in some other thread you have no control over) and will finish some time in the future. You can ask this Future object to see whether the future already came or not (processing is done). You are not creating any thread yourself.
Think about ExecutorService. You are submitting some task to be done and waiting for a result. But instead of blocking, you get a Future which will give you back the result as soon as your submitted task reaches the thread pool and is processed.
Will the callback happen on the same thread, or will it run on the "main" thread
Neither. Your thread (the one that called AsyncHttpClient.execute()), by the time the response came back, is most likely doing something completely different. Maybe it serves another client or is already dead. You cannot just call arbitrary code on behalf of some thread.
In fact, this piece of code will be executed by internal NIO thread created by AsyncHttpClient library. You have absolutely no control over this thread. But you have to remember that this will happen asynchronously, so synchronization or some locking might be required if you access global objects.
You can check that by that piece of code:
import java.io.IOException;
import com.ning.http.client.AsyncCompletionHandler;
import com.ning.http.client.AsyncHttpClient;
import com.ning.http.client.Response;
public class Asink {
public static void main(String... args) throws IOException {
AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
asyncHttpClient.prepareGet("http://www.google.com/").execute(
new AsyncCompletionHandler<Response>() {
#Override
public Response onCompleted(Response response)
throws Exception {
// Do something with the Response
// ...
String threadName = Thread.currentThread().getName();
System.out.println(threadName);
return response;
}
#Override
public void onThrowable(Throwable t) {
// Something wrong happened.
}
});
}
}

Implementing long polling in an asynchronous fashion

Is it possible to take an HTTPServletRequest away from its thread, dissolve this thread (i.e. bring it back to the pool), but keep the underlying connection with the browser working, until I get the results from a time-consuming operation (say, processing an image)? When the return data are processed, another method should be called asynchronously, and be given the request as well as the data as parameters.
Usually, long pooling functions in a pretty blocking fashion, where the current thread is not dissolved, which reduces the scalability of the server-side app, in terms of concurrent connections.
Yes, you can do this with Servlet 3.0
Below is the sample to write the alert every 30 secs(not tested).
#WebServlet(async =“true”)
public class AsyncServlet extends HttpServlet {
Timer timer = new Timer("ClientNotifier");
public void doGet(HttpServletRequest req, HttpServletResponse res) {
AsyncContext aCtx = request.startAsync(req, res);
// Suspend request for 30 Secs
timer.schedule(new TimerTask(aCtx) {
public void run() {
try{
//read unread alerts count
int unreadAlertCount = alertManager.getUnreadAlerts(username);
// write unread alerts count
response.write(unreadAlertCount);
}
catch(Exception e){
aCtx.complete();
}
}
}, 30000);
}
}
Below is the sample to write based on an event. The alertManager has to be implemented which notifies AlertNotificationHandler when client has to be alerted.
#WebServlet(async=“true”)
public class AsyncServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse res) {
final AsyncContext asyncCtx = request.startAsync(req, res);
alertManager.register(new AlertNotificationHandler() {
public void onNewAlert() { // Notified on new alerts
try {
int unreadAlertCount =
alertManager.getUnreadAlerts();
ServletResponse response = asyncCtx.getResponse();
writeResponse(response, unreadAlertCount);
// Write unread alerts count
} catch (Exception ex) {
asyncCtx.complete();
// Closes the response
}
}
});
}
}
Yes, it's possible using Servlet spec ver. 3.0. Implementation I can recommend is Jetty server. See here.

Categories

Resources