How do you to detect the end of a thread via ThreadId? - java

Talking Java Servlets here... I'm working on creating my own "Per Request Context" and I was looking to tie the "Per Request Context" object to the Thread.currentThread().getId() value.
Instead of passing around this context object everywhere I was planning on checking the current threadid when a user calls a function that is Per Request based and automatically getting the Context object out of a hashtable for that threadId.
I would use the code this like..
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
MyFramework.EnterContext();
try {
// do stuff here that leads to other classes on the same thread
// Access current context via static MyFramework.getCurrentContext()
}
finally { MyFramework.ExitContext(); }
}
However I would like to protect my application automatically from any potential user that does not call ExitContext(). In C# there is an event handler on the thread object for onexit...(think I wrong on this) is there some way to detect or poll when a thread exits? I'm currently storing only the threadId (long).
Any ideas?

unfortunatelly, there is no such feature built in for threads in Java. Besides, thread id is only guaranteed to be unique at any one time, but may be reused eventually when the thread dies (from the docs). however, the servlet framework that you are using may be implementing such feature (just a speculation).
i would recommend you implement a servlet filter, and tell your users to include it in their web.xml. with this you can be sure the client code always gets correctly wraped in your thread context.

A ThreadLocal seems to fit your use perfectly. A ThreadLocal object can provide a way to store a variable per thread. The internal workings of this class are very much of what you describe, it uses a map to give thread-local variables.
Something like this should do the trick:
private static final ThreadLocal<UserContext> userContext = new ThreadLocal<UserContext>();
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
MyFramework.EnterContext();
try {
UserContext context = userContext.get();
//if you used the set method in this thread earlier
//a thread local context would be returned using get
}
finally { MyFramework.ExitContext(); }
}
As for your other problem, you can use an observer pattern and notify when the thread completes its task.

Related

Hold HTTP servlet request threads for reloading business config object

I need to Hot load or Reload business configuration / object at runtime in http servlet.
Config object is generated by reading a file during servlet init(). I need to reload this object when file is changed / updated..
public void init() {
Config config = initializeConfigFile();
}
Task 1 would be to have a thread periodically monitor file contents and if changed re-create config object from changed file.. I think this can be achieved by having some hash like md5 on file contents.. check if new hash changed..
public void run() {
// Read file
// Generate hash of file contents
// Compare with previous hash
// If different set a flag to hold threads
// configFileChanged = true;
}
Task 2 hold request threads until new config object is created. As this happens at runtime there might be request threads already accessing old config object and I can't just swap the config object as this might produce unexpected behavior. So I need to wait until all the threads already accessing the old config are done.
So I need suggestions for task 2.. I have not explored much of java advanced threading and queue based API's
For now thinking of some queue which holds request threads.
public void doGet(HttpServletRequest req, HttpServletResponse resp) {
if (configFileChanged) {
synchronized (ActionServlet.class) {
while (configFileChanged) {
if (queue.isEmpty) {
config = initializeConfigFile();
configFileChanged = false;
} else {
sleep(2000);
}
}
}
}
queue.insert(Thread.currentThread());
// perform task using config object
queue.remove();
}
Also suggest improvizations for task 1, if any..
Thanks..
Bad way for both tasks:
For task 1:
Checking file regularry is not a logical process while you can have an observer/monitor for the file, in other word, check the new config once the file is changed(file monitor using java.nio.file)
For task 2:
If and if the container is not configured/overridden to create new instance for each request. --> The default/std behavior is having ONE object of the Servlet, and invoke the instance for each request via a thread, so for this a synchronized void reload() method would help.
During the reload() method run, because it locks the Servlet object, All new requests will be hold till the reload() finishes it's job.
public void doGet(HttpServletRequest req, HttpServletResponse resp) {
//servlet business
}
//the reload is called by the file monitor
//The synchronized method will hold all new requests
synchronized void reload(){/*applying new configs*/}
Besides having a file(external) observer might not look safe and logical, I suggest having an external applciation which monitors the file and informs the web context by calling a servlet(maybe /friends/reload_config) where there is a servlet mapped to /friends/reload_config which will call reload() method.
You may check the request ip in /friends/reload_config servlet in order to ensure the request is generated by local app(not from net)

Outputstream between threads

I have an ajax method on my servlet that could be running at the same time for the same user. Sorry if I use the wrong words to describe the problem but it's how I understand it so far (don't know much about threading).
Anyways here's the method
private void ajaxPartidas() throws ServletException, IOException {
//Variables necesarias
DataSource pool = (DataSource) session.get().getAttribute("pool");
Recibo registro = null;
int id = -1;
try{ id = Integer.parseInt(request.get().getParameter("id"));}catch(NumberFormatException e){}
if(id > 0){
registro = new Recibo(id);
if(!registro.obtener(pool))
registro = null;
registro.setPartidas(Partida.obtenerRegistros(pool, registro.getId()));
}
response.get().setContentType("application/json");
response.get().setHeader("Content-Type", "application/json; charset=utf-8");
response.get().getWriter().print((new Gson()).toJson(registro.getPartidas()));
}
This method is being called via ajax, it works fine the 1st time it gets called, but second time (on same id) and it returns a NullPointer on the getWriter() line. I've looked around and everyone seems to pinpoint the problem to threads. Now a little bit more of context would be that everytime the servlet enters in the
doPost(request, response)
I assign a threadlocal variable declared like so in the global vars
private static ThreadLocal<HttpServletResponse> response = new ThreadLocal<>();
and I assign it the response
Home.response.set(response);
in the doPost() method.
How would I go about making the getWriter() threadsafe?
Not sure why you're assigning the response to a class level ThreadLocal? Each new user generated request has a clean request and response object. getWriter and all methods on the servlet class are threadsafe as long as you follow the correct guidelines for using a Java Servlet. A general rule with Java Servlets is that as long as you don't use class level variables, you are thread-safe.
Instead of using a ThreadLocal, you need to pass the request and response objects as parameters to your ajaxPartidas method and then call it as you normally would. So your doPost method would look like this
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ajaxPartidas(request, response);
}
The concurrency issues are already handled by the Servlet class itself, you just need to write the business logic. See this answer in a similar thread for more details on using a Java Servlet with Ajax: https://stackoverflow.com/a/4113258/772385
Tomcat creates a new Request and Response for EVERY user request. So they are already threadsafe (unless you go in and create a new Thread). Besides, make sure you are passing "id" and is getting set properly. I think it's the "registro" object on the same line as getWriter() that's causing the NullPointerException.

Apache Tomcat Servlet threads not finishing

I've written a servlet deployed in tomcat.
public class myServlet extends HttpServlet {
public int NumberOfThreads = 0;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println(NumberOfThreads);
NumberOfThreads++;
....
..a lot of code..
....
NumberOfThreads--;
}
}
Now when I get too many requests the NumberOfThreads keeps rising and never goes down again. My problem is that there is a few tasks that have to be performed by each request before leaving.
I just don't understand why this happens. Is it that some of the threads get lost on the way? I really need each request to say properly goodbye.
Thanks
You are doing it wrong.
System.out.println(ManagementFactory.getThreadMXBean().getThreadCount());
Alternatively, just use JMX/JConsole.
As you're speaking about this taking a long time and requests are being cancelled (in your comment): Yes, the whole doGet will be executed, even when the user cancelled the request: Request cancelling is only on HTTP level. However, when the request is cancelled, the HTTP connection might be closed, resulting in exceptions when you actually want to write to the response's output stream.
Combining the other answers already given:
You'll need to synchronize your modifications of the counter (see didxga's answer)
there's probably a better way to solve your problem (as Ravi Thapliyal states)
use try{ ... } finally { ... } to ensure you actually decrease the counter
make your code more maintainable by moving it out of the servlet into a proper, non-UI, class
Pseudo code:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
synchronized(this){NumberOfThreads++;}
doSomething();
} finally {
synchronized(this){NumberOfThreads--;}
}
}
Also, be aware that long-running execution in the actual http connector thread blocks all subsequent http requests - it might be a good idea to trigger background processing and just query that background process in later HTTP requests. That way you can also queue multiple invocations and not start a huge number of background threads at the same time. Keep in mind, there's a limited number of HTTP request handlers.
I'm assuming the try/finally will be your main problem (or an endless loop in your code) - synchronizing will solve rare race conditions, especially as you're speaking of a lot of code executed in this servlet.
The different servlet threads are caching NumberOfThreads. You have to mark it as volatile.
public volatile int NumberOfThreads = 0;
But, I have a feeling that there are better ways of doing what you probably want to achieve with this code.
You need to synchronize modification to NumberOfThreads
public class myServlet extends HttpServlet {
public int NumberOfThreads = 0;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println(NumberOfThreads);
synchronized(this){NumberOfThreads++;}
....
..a lot of code..
....
synchronized(this){NumberOfThreads--;}
}
}

How to make a servlet respond to multiple requests?

I have a task that I want to wrap in a servlet to provide the ability to run the task remotely, by http request.
I know I can achieve this with REST API, but currently I assume (and please correct me if I'm wrong) that a simple servlet will do.
One of the things I want to achieve is that if a request to the servlet is made while another request is still processed, I'll get an appropriate response - "Task is already running".
I've built a simple servlet, using servlet-3.0, that calls the jar I want to run, but when I make 2 requests, the second one is not processed until the first one is finished.
EDIT:
My servlet is a simple http serlvet. service method overriden.
I have a system.out.println("a") in the start.
when I call the servlet in debug mode and then (while stopped at breakpoint) call it again, the message is printed only one time and printed the second time when I release the breakpoint and the first run finishes.
First of all, this does not seems like REST at all. If you really just want to spawn a (single) background task, make sure you do it in a separate worker thread, not the request thread.
Maybe you need a lock:
public class Task extends HttpServlet {
// for singleton
//private volatile boolean running = false;
// or try this:
public static boolean running = false;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
if(running){
PrintWriter out = response.getWriter();
out.println("running");
return;
}
synchronized(Task.class){
if(!running){
running = true;
// run the task
running = false;
}
}
}
}

in servlet I want to have a response.print() while another thread is running

I have a cumbersome object which has to work in background , I create a servlet which will call this object and for running the object I've implemented the Runnable interface inside my servlet like following :
public class myObject extends HttpServlet implements Runnable
{
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
res.print("<br/> running...");
res.flush(); //doens't help
Thread t = new Thread(this);
t.run();
}
public void run()
{
res.print("<br/> running...");
res.flush();//doesn't helper either
cumbersomeObject.workHard();
}
}
How can I print this simple line and then send 200 status to user and my servlet work in background happily ever after?
Change t.run() to t.start(), your thread is not running in background, but blocking in foreground. BTW how does this compile? How can run() access res variable?
However it looks like you are trying to send some data to a user via res response object from a thread. This won't work, see HttpServletResponse seems to periodically send prematurely for a detailed discussion.
You're making a fundamental mistake. The HTTP servlet request and response objects are tied to the current HTTP request thread. Once this thread finishes (i.e. when the HTTP request/response finished), then the associated HTTP servlet request and response objects are trashed and completely useless. So if you use those objects in a different thread after the initial HTTP request/response finishes, then you'll get exceptions in all colors because they point nowhere to.
Manually spawning new thread on a per-request basis is also a terribly bad idea. Threads are not cheap and definitely not unlimited available. Rather use a pool of 5~10 threads or something. If you have such a thread pool, then you could just submit a task to it, associate it with some unique key in the HTTP session or maybe even in a database along the logged-in user ID. You can then just poll in every subsequent request if the task is finished or not (i.e. it has stored the result there where you'd expect to see it).

Categories