I have a jsp application (using Spring) that uses a couple of global variables. I need multiple people to be able to use this program concurrently, however. What is the best way to go about making it thread-safe such that each instance of the program is independent of the others?
::EDIT:: Am I okay if I just don't use any singleton objects?
Each request is handled in its own thread. These threads are managed by the servlet container. It is not a good idea to use static global variables in a servlet. All instance variables are common to all threads, therefore it can lead to ambiguous state.
I recommend saving this type information in a scope variable (application,session, request, page, etc).
If you have to use a global variable then you will need to synchronize the access to it to avoid unknown states.
A typical container uses a thread-per-request model, so you have an easily-recognizable boundary built right in. The general rule is to never store any state in any object that is visible to multiple requests (threads) unless that state is effectively immutable. For example, a singleton controller like this
#Controller
#RequestMapping("/schedule")
class MyController {
private Scheduler scheduler;
#RequestMapping(method = RequestMethod.POST)
public void scheduleSomething(Foo foo) {
scheduler.schedule(foo);
}
}
is stateful--the schedular field holds state--but the state is initialized at startup and remains constant across all requests/threads. If you had a singleton controller like this, on the other hand:
#Controller
#RequestMapping("/schedule")
class MyController {
private Scheduler scheduler;
private Foo foo;
#RequestMapping(method = RequestMethod.POST)
public void scheduleSomething(Foo foo) {
this.foo = foo;
scheduler.schedule(this.foo);
}
}
That is absolutely not safe for concurrent access because all requests go to this same controller, and foo will be constantly changing in a non-thread-safe way. Follow this line of reasoning through your entire application, and you'll be safe.
Related
This question already has answers here:
Must Spring component classes be thread-safe
(4 answers)
Closed 1 year ago.
Are methods (without using class variables) thread safe when using Spring Boot ?
I came across carious links where they mentioned instance variables aren't safe always ?
My doubt is how can I create a race condition ? Is the below code thread safe ?And if yes then how can i make it thread - unsafe without using class variables
#RestController
public class GreetingController {
#Autowired
private GreetingService greetingService;
#GetMapping("/hello")
public void greeting(#RequestBody MyUser myUser) throws Exception {
greetingService.getData(myUser);
}
#Service
public class GreetingService {
#Autowired
private DBService dBService;
public void getData (MyUser m ) throws InterruptedException
{
dBService.getData(m);
}
#Repository
public class DBService {
public MyUser getData(MyUser myUser) throws InterruptedException {
System.out.println( "message before: " + myUser.getA() + " Thread : " +Thread.currentThread().getName());
Thread.sleep(18000);
System.out.println( "message after " + myUser.getA() + " Thread : " +Thread.currentThread().getName());
return myUser;
}
In resume: yes, apparently, this code is thread-safe. Since you're using Servlets, each request will be served in a different thread provided by the servlet container (if you're using the default configurations for Spring Boot, the servlet container is a Embedded Tomcat).
Why apparently? Because this code is only thread-safe if the instances of objects declared in the class scope are also thread-safe (i.e GreetingService must be thread-safe)
Take your own example:
The Thread#sleep executed in a first request has no effect on the subsequent ones (i.e other request will not be blocked) because the subsequent ones are served on different threads, as said above.
You will be fine as long as you don't assign new values to the global variables during a request life cycle.
By default (see Does spring dependency injection create singleton objects?), objects injected by spring dependency injection (#Autowired in your case) are singletons.
In your example, there will be exactly one instance each of the controller, service, and repository. So, not inherently thread-safe.
The usual pattern for these classes is as you have shown - use class-level variables only for instances of objects that are themselves thread-safe.
Do not keep any state in class-level variables unless you want that data shared (which is rare), and your code will be thread-safe.
If you do share state on purpose, make sure that you take care to make access to that state thread-safe.
I wrote this class here
#Component
public class LoginDao {
#Autowired
private JdbcTemplate jdbcTemplate;
public List<Map<String, Object>> getUser(final String username, final String password) {
return jdbcTemplate.queryForList("select * from users where username=? and password=?", new Object[]{username, password});
}
}
Now, it is used by a managedbean in JSF, which is just a bean created and used when a request is made (if you use default scope).
#ManagedBean
public class Login implements Serializable {
#ManagedProperty("#{loginDao}")
private LoginDao loginDao;
//..do something with loginDao
}
I am scared that this is completely broken because what if when the Login bean created by JSF goes to use that loginDao, which is an injected object, and see that loginDao's field jdbcTemplate to be null?
This might happen if the Login bean used to handle the request, is going to run in a separate thread if the Webserver uses that separate thread to handle that request and since LoginDao's field jdbcTemplate is not final and set in the constructor before the running of the Login bean, couldn't that jdbcTemplate be seen as null in the Login instance? Is the way to fix this to make the jdbcTemplate to be volatile?
Also, now this makes me question everything I ever wrote with spring and JSF. Is it impossible to write thread-safe classes when using the #Autowired annotation unless you use the volatile keyword on that field?
I am really worried about using a dependency injection framework now. I mean, is there even a guarantee that objects that were injected by the container will not be seen as null for its reference or in a non up to date state?
Autowired beans are injected during initialization, so in this case jdbcTemplate should never be null when handling a request. However, if you want to be completely sure, yo can inject it through a constructor, which is the recommended method:
#Component
public class LoginDao {
private final JdbcTemplate jdbcTemplate;
#Autowired
public LoginDao(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
public List<Map<String, Object>> getUser(final String username, final String password) {
return jdbcTemplate.queryForList("select * from users where username=? and password=?", new Object[]{username, password});
}
}
Effectively as you say, its very possible that multiple requests will be handled by different threads, and what would happen depends entirely on the defined scopes:
The default scope in spring is 'singleton', so in this case LoginDAO will have only one instance in the application serving all requests. In your posted code this is not a problem, as JdbcTemplate is thread-safe.
Also, now this makes me question everything I ever wrote with spring
and JSF. Is it impossible to write thread-safe classes when using the
#Autowired annotation unless you use the volatile keyword on that
field?
Its completely possible. And it will depende mostly on what you need. You can have a singleton bean which performs its operations in a thread-safe manner (dependes on your code and the libraries you use), or you can have non-thread safe bean working with a 'request scope' (ie: one bean instance for each request), or anything in the middle (there are 5 scope types in spring).
Setting fields as volatile if for a complete different purpose. the volatile keyword indicates that a field value will be continuously being modified by multiple threads, so the JVM will not cache its value inside threads to prevent race conditions, and will manage asignations in an atomic way. This will only protect the field value, but if the value is an object, it will not protect the values inside that object.
I am really worried about using a dependency injection framework now.
I mean, is there even a guarantee that objects that were injected by
the container will not be seen as null for its reference or in a non
up to date state?
At least in my experience with spring, i have never encounter that problem. Spring does a very good job initializing an preparing everything on startup so you don't have to worry about that. However, the constructor autowiring method indicated previously is recommended precisely because give the programmer more safety about exactly your issues.
Does CDI allows pooling in some way?Because I thought this is a feature of EJB beans but Adam Bien says in this screencast that container chooses whether to create new instance of class through reflection or use the existing one. So if I have for example these two beans
#RequestScoped
public class RequestBean {
public void doIt() {
}
}
#SessionScoped
public class SessionBean {
#Inject
private RequestBean bean;
public void doSomething() {
bean.doIt();
}
}
the question is - is there always new instance of RequestBean created upon calling doSomething or does CDI container somehow manage instances in pool?
The first one is scoped to the request, so a new instance is created for each request. The second one is scoped to the session, so a new one is created for each session.
CDI doesn't pool and recycle the objects, because it has no idea if the objects are stateful or not, and you don't want, in a request, to get back the state that a bean had in a previous request. That would ruin the whole point of the request/session scope.
Unless beans are really costly to create (because they start a new connection or something like that), pooling them doesn't bring any advantage. Short-lived objects are very fast to create and garbage collect nowadays. And if the bean is really expensive to create, then it should probably be a singleton.
I have a jax-ws web service with several handlers. I have a particular object that is performance wise costly to initiate. I need this object to process each and every request come to web service.
Is it a solution to put this object to a static block? Since static block is created at class loading time will it give a performance improvement. But still does it achieve what I need. I need same object kept in the memory and reused for all requests. But as I know in a web service each request is allocated to a thread object in the static block will not be shared by threads. it is?
Expecting a bit of explanation here guys.
Thank you
A static block is a piece of code which is run once when the class is initialized by the class loader. You might use it to set up your complex object and then keep a reference to it in a static variable like so:
public class MyClass {
private static final LanguageLookup languageLookup;
static {
languageLookup = new LanguageLookup ();
languageLookup.loadData();
}
public Response handleRequest(Request request) {
String language = languageLookup.lookup(request.getCountryCode());
response.setLanguage(language);
return response;
}
}
If you do this in a multi-threaded environment like a servlet or a webservice you need to be sure that the state of LanguageLookup cannot change after its initialization. If it uses dependencies of its own for operations other than its initialization, these must also be stateless.
I think it is generally not a good idea to do it this way because you are hard-wiring your class to the LanguageLookup, making it tightly coupled and harder to unit test.
It is very easy to use a dependency injection framework like Spring to set up singletons:
When a bean is a singleton, only one shared instance of the bean will
be managed and all requests for beans with an id or ids matching that
bean definition will result in that one specific bean instance being
returned.
In the application context you would have something like:
<bean name="languageLookup" class="com.acme.foo.LanguageLookup" singleton="true" init-method="loadData"/>
And in your code:
public class MyClass {
private LanguageLookup languageLookup;
public Response handleRequest(Request request) {
String language = languageLookup.lookup(request.getCountryCode());
response.setLanguage(language);
return response;
}
// called by Spring
public void setLanguageLookup(LanguageLookup languageLookup) {
this.languageLookup = languageLookup;
}
}
I wondering if I should exspect any problems when I autowire threads with prototype scope.
The thread:
...
#Service
#Scope("prototype")
public class MyThread extends Thread {
...
}
The thread starting class:
...
public class ThreadStarter {
#Autowired
private MyThread myThread;
public void startThread(){
myThread.start();
}
}
The starting class will be called from a webservice implementation.
Are there any pitfalls I should take into consideration?
Well it reallty depends on what the thread class instance does.
Think of Servlet doGet and/or doPost methods. If you're being stateless and don't keep values in wider scopes (such as session or context) you're fine with not troubling yourself about which instance of your servlet will be called when. However if you are being statefull (get/put objects to the session scope for example) then you need to synchronize that servlet instance's access to said scope (synchronized(session)) or serialize the way requests are being treated by the servlet threads.
I think here you're pretty much in the same situation. You want to make your thread instance to be prototype scoped (and thus have a new instance created each time an injection is needed) if you are infact stateful and share data between your threads, and you can leave it to the default scope of singleton if that thread's run() method is stateless as far as data outside it is concerned.
Nope, autowiring only affects which bean is choosed to fulfill a dependency- as long as you are not meddling with the ApplicationContext (i.e. adding/modifying beans concurrently), no weird stuff should happen.
In your example ThreadStarter will be injected a new instance of MyThread everytime it is instantiated- which I hope is what you want.