I am developing a java servlet that while running, starts different objects methods in new threads. Those threads should access a variable that describes the specific servlet instance, say jobId. For this reason, i declared the jobId variable as static. The servlet constructor is calculating this value for each servlet instance (call).
I was wandering if the servlet is called few times at the same time, the static jobId variable is shared between the calls, which means that some threads will get the wrong jobId, or it is calculated once for each call- so the threads that a specific servlet started will use the jobId calculated for this specific servlet (which is the way i want it to work).
Any ideas?
Thanks a lot!
A servlet is created only once on webapp's startup and shared among all requests. Static or not, every class/instance variable is going to be shared among all requests/sessions. You would not like to assign request/session scoped data to them. Rather declare/assign them as methodlocal variable. E.g.
public class MyServlet extends HttpServlet {
private static Object thisIsNotThreadsafe;
private Object thisIsAlsoNotThreadsafe;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Object thisIsThreadsafe;
thisIsNotThreadsafe = request.getParameter("foo"); // BAD! Shared among all requests.
thisIsAlsoNotThreadsafe = request.getParameter("foo"); // BAD! Shared among all requests.
thisIsThreadsafe = request.getParameter("foo"); // Good.
}
}
There exist the legacy and deprecated SingleThreadModel interface which you can let your servlet implement to force creation during every request. But this is a bad design and unnecessarily expensive. That's also why it's deprecated.
See also:
Servlet instances and multithreading
How do servlets work?
static means that every instance will access to the same value.
So every user connected to the servlet will access to the same value. Your jobId will be probably wrong when 2 users or more are connected together.
You have to get your own value a each connection and store it somewhere else.
Resources :
static variable in servlet - when can we use?
On the same topic :
Sharing a static object between a servlet and a webservice
Static variables are shared. Static variables don't belong to any one instance, they are accessible by all instances of the class. When you are using a constructor, that is used to create one object (one instance of the class), setting a static variable in a constructor typically doesn't make sense because it's something that is outside the scope of the object you're creating.
As for what would work, you could put the jobId in the HttpSession and then each user would have their own copy of it.
The instantiation policy for servlets is not defined in the servlet spec (as far as I can remember, anywho) but the usual behavior seems to be to create only one instance per servlet configuration. So, in your case, every request would use the same variable.
If I were you, I'd consider to send the jobId as a parameter to the Runnables you're running the threads with. For example, in stead of this:
public class HelloWorld extends HttpServlet {
private static long jobId;
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
jobId = Long.parseLong(request.getParameter("jobid");
new Thread(new Worker()).start();
}
static class Worker implements Runnable {
#Override
public void run() {
doSomethingWith(jobId);
}
}
}
Refactor away the static variables like this:
public class HelloWorld extends HttpServlet {
// private static long jobId; -- delete, no longer needed
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
long jobId = Long.parseLong(request.getParameter("jobid"); // local variable
new Thread(new Worker(jobId)).start(); // send jobId as parameter
}
static class Worker implements Runnable {
private final long jobId; // non-static; every instance has one
public Worker(long jobId) { // allow injection of jobId
this.jobId = jobId;
}
#Override
public void run() {
doSomethingWith(jobId); // use instance variable instead of static
}
}
}
Easier to read, no concurrency problems - pure win.
Related
Hi I have created a private method inside the servlet.
The method will be called from the post method. My questions is, will it be threadsafe since it will be called via ajax by many many user?
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
callPrivateMethod();
}
private static void callPrivateMethod(){
}
As long as callPrivateMethod() is thread safe, i.e. it does not use a class member variable, then you will be fine.
No, your private method won't be thread safe as doPost is not thread safe in servlet.
It is static method with immutable objects as parameters in your case (no parameters) is Thread safe
Servlets should be stateless. Hawever, if you need to use class members or any other thread-unsafe element, you always could use "synchronized" sentences.
The servlet is instanced only once at loading. If you want to make call to callPrivateMethod() thread safe, you can put it inside a synchronized block.
private Object mutex = new Object();
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
synchronized (mutex){
callPrivateMethod();
}
}
private static void callPrivateMethod(){
}
I have an application running on tomcat and I have a static pool (HashMap) where I am storing an object each time a thread is created in tomcat through a request and I am deleting the entry from the HashMap when the thread dies. Just to make it clear here is a simple example of what I am doing.
This is my pool
public class CustomerPool{
public static Map<String, Customer> customerPool = new HashMap<String, Customer>();
public static void createSession() {
String threadName = Thread.currentThread().getName();
Customer c = new Customer();
customerPool.put(threadName, customer);
}
public static void terminateSession(){
String threadName = Thread.currentThread().getName();
customerPool.remove(threadName);
}
}
And my servlet
public class CustomerServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) {
CustomerPool.createSession();
//the rest of my code
CustomerPool.terminateSession();
return;
}
}
Due to some exceptions that I am receiving (which are specific to my application and there not point to list them) I believe that sometimes entries are not getting removed from the pool.
I want to produce a report of the pool which will show how many entries are currently into the pool and for which of them the thread does not exist. Is it possible in Java to check if a thread is alive by knowing only the thread name?
Thanks a lot
You should be using a ThreadLocal for this. If the thread dies, the ThreadLocal will be cleaned up automatically since it's a class variable for the Thread.
You can enumerate all the threads in the JVM, but it has a code 'smell' to me if you have to do that for proper function of your program.
I am working on a project that includes communication between computer application and embedded devices over serial port in Master-Slave mode.
The application will serve as Master to multiple embedded devices working as Slaves.
The communication part is almost complete. But now, I am refactoring it as an API.
So, it can be used over multiple projects or by many developers with very less configurations.
I am not very good in API design, even it's the first time, I am creating an API.
Now, I am stuck on following issue:
Consider this scenario:
/*
* API Part
*/
public abstract class AbstractSlave {
// Some fields, constructor and other methods.
final void handle(Request request, Response response) {
// Some operations before starting worker thread.
SlaveWorker worker = new SlaveWorker(request, response);
worker.start();
}
}
public class SlaveWorker extends Thread {
// Constructor
#Override
public final void run() {
work(request, response);
}
public void work(Request request, Response response) {
}
}
AbstractSlave class starts a worker thread to work upon the request and response, so that long-running operations cannot cause the loss of upcoming responses from slaves.
Now, here is the "API usage part":
/*
* API Usage Part
*/
public class Slave extends AbstractSlave {
// Constructor
}
public class MyWorker extends SlaveWorker {
// Constructor
#Override
public void work(Request request, Response response) {
super.work(request, response);
// My work to be done upon request and response.
}
}
But as we can see, AbstractSlave creates SlaveWorker instances.
So, SlaveWorker work() method will be called, instead of MyWorker.
How to make AbstractSlave class to call MyWorker work() method?
NOTE:
As it's an API design, AbstractSlave would not know, there is a MyWorker class. So, MyWorker instances cannot be created directly in place of SlaveWorker.
handle() method of AbstractSlave can/meant not be overridden, because there are some operations, that need to be performed before starting worker thread.
I think the key point would be to let the client of your API create the instance of SlaveWorker (or any subclass), so that he can customize the work() method.
IMO you should provide a Worker interface in your API (interface is less constraining than an abstract class):
public interface Worker {
public void work(Request request, Response response);
}
And AbstractSlave's method should be like:
public abstract class AbstractSlave {
private final Worker worker;
public AbstractSlave(Worker worker) {
this.worker = worker;
}
final void handle(final Request request, final Response response)
// Some operations before starting worker thread.
Thread t = new Thread() {
public void run() {
worker.work(request, response);
}
};
t.start();
}
}
There are different ways to do this, but one way is to add a configureJob method to your AbstractSlaveand use this to tell your AbstractSlave class about MyWorker.
public class SlaveManager {
private Class workerClass = SlaveWorker.class;
public void configureJob(Class clazz){
workerClass = clazz;
}
final void handle(Request request, Response response) {
// Some operations before starting worker thread.
Worker worker = workerClass.newInstance();
worker.start(request, response);
}
}
public interface Worker {
public void work(Request request, Response response);
}
In your main method, just call SlaveManager::configureJob(MyWorker.class) before you call SlaveManager::handle().
Now, I've kept things simple above by using Object.newInstance() to create the Worker, but this is not a recommended general practice. It's more customary to use a WorkerFactory instead, but I didn't want to introduce a new class and a new design pattern in case you were unfamiliar with the Factory Pattern.
I have a a servlet called Statelessservlet which instantiates a new stafeful object every time. Do I need to provide synchronisation to this stateful object?
Here's the code:
public class StatelessServlet extends HttpServlet {
#Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
StatefulObject stObj = new StatefulObject(Integer.parseInt(req.getParameter("id")));
stObj.performSomeStatefulOperation();
...
}
}
class StatefulObject {
private int id;
public StatefulObject(int id) {
this.id = id;
}
//Is synchronized really needed here???
public synchronized void performSomeStatefulOperation() {
id++;
}
}
As per Brian Grotz JCIP each stafeful object should be synchronised, so Ideally we should synchronise this method?
If each interaction with your server creates a new object and discards it, then it's relatively safe not to have synchronization (there is no shared state between multiple threads accessing the service at the same time).
If, on the other hand, those objects are reused, you must synchronize that method.
Also, if, for instance, your performSomeStatefulOperation changes state of some shared data, then you should synchronize it, unless you took other steps to guarantee it's thread safety (using locks, for instance).
To sum up, it depends on what you're doing in your method. From what you show, there is no need, if there could be a problem from multiple invocations of that method (because it updates shared state), then you should synchronize it.
No synchronization needed since each thread gets its own instance of StatefulObject which is unreachable to other threads.
Hey I want to implement a Java Servlet that starts a thread only once for every single user. Even on refresh it should not start again. My last approach brought me some trouble so no code^^. Any Suggestions for the layout of the servlet?
public class LoaderServlet extends HttpServlet {
// The thread to load the needed information
private LoaderThread loader;
// The last.fm account
private String lfmaccount;
public LoaderServlet() {
super();
lfmaccount = "";
}
#Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
if (loader != null) {
response.setContentType("text/plain");
response.setHeader("Cache-Control", "no-cache");
PrintWriter out = response.getWriter();
out.write(loader.getStatus());
out.flush();
out.close();
} else {
loader = new LoaderThread(lfmaccount);
loader.start();
request.getRequestDispatcher("WEB-INF/pages/loader.jsp").forward(
request, response);
}
}
#Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
if (lfmaccount.isEmpty()) {
lfmaccount = request.getSession().getAttribute("lfmUser")
.toString();
}
request.getRequestDispatcher("WEB-INF/pages/loader.jsp").forward(
request, response);
}
}
The jsp uses ajax to regularly post to the servlet and get the status. The thread just runs like 3 minutes, crawling some last.fm data.
What you need here is Session listener. The method sessionCreated() will be called only once for every browser session. So, even if the user refreshes the page, there will be no issues.
You can then go ahead and start the thread for every sessionCreated() method call.
Implement javax.servlet.SingleThreadModel => the service method will not be executed concurrently.
See the servlets specification.
Hypothetically it could be implemented by creating a Map<String,Thread> and then your servlet gets called it tries to look up the map with the sessionId.
Just a sketch:
public class LoaderServlet extends HttpServlet {
private Map<String,Thread> threadMap = new HashMap<>();
protected void doPost(..) {
String sessionId = request.getSesion().getId();
Thread u = null;
if(threadMap.containsKey()) {
u = threadMap.get(sessionId);
} else {
u = new Thread(...);
threadMap.put(sessionId, u);
}
// use thread 'u' as you wish
}
}
Notes:
this uses session id's, not users to associate threads
have a look at ThreadPools, they are great
as a commenter pointed out: synchronization issues are not considered in this sketch
Your first task is to figure out how to identify users uniquely, for instance how would you discern different users behind a proxy/SOHO gateway?
Once you have that down it's basically just having a singleton object serving a user<->thread map to your servlet.
And then we get into the scalability issue as #beny23 mentions in a comment above... I absolutely concur with the point made - your approach is not sound scalability-wise!
Cheers,
As I understand, you want to avoid parallel processing of requests from the same user. I'd suggest you other approach: associate lock with each user and store it in session. And before start processing of users request - try to get that lock. So current thread will wait while other requests from this user are handling. (Use session listener to store lock, when session is created)