Thread safety in Spring Boot with Instance variables [duplicate] - java

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.

Related

Why does the service class variables persist on every new hit? [duplicate]

This question already has answers here:
What is the default bean scope used by Spring Boot?
(2 answers)
Closed 1 year ago.
I am working on the Spring Boot project. I have a controller which uses my service class. Here is the situation, in my service class I have few class variables which I use as counters, the issue is that whenever I hit my endpoint, the values of my counter variable persists for each hit, meaning if on first request counter value is 1 then on the second hit it becomes 2 so on and on.
Shouldn't the class variables get reset for each new request? I mean the service class should be new object for each request, right?
Here is essentially what I am doing.
My controller:
#Getmapping(path='/learningSpringBoot')
public RequestEntity<String> myMethod() {
myServiceObject.learnSpring();
}
And in my service:
#Service public class Myservice {
private int counter;
public void learnSpring() {
System.out.println("counter : "+ counter);
counter++;
}
}
Please let me know if I'm doing something fundamentally wrong here or absolutely missing some concept.
Shouldn't the class variables get reset for each new request? I mean the service class should be new object for each request, right?
No, the #Service class is instantiated when you start your app since it's a #Bean.
Check out how scopes and different annotations work. By default #Service is #Scope("singleton") so it does not get instantiated per-request and thus the variables are keeping their states.

How to access object without passing it as parameter?

Is there a way to autowire an object that needs to be re-instantiated frequently?
I am using Netflix's DGS + spring boot framework, and basically storing the user authentication details in a custom context which is created for each request. I am trying to avoid adding context to the method signature because of the large amount of refactoring needed.
e.g.
public Result dataFetcher(DataFetchingEnvironment dfe) {
// this context contains user details which is used for authorization
// instantiated for every request
setRolesInContext(dfe);
MyCustomContext context = DgsContext.getCustomContext(dfe);
// trying to avoid adding context as an extra param e.g. dataFetcherHelper(context)
dataFetcherHelper(); // this calls other helper methods from other classes
}
I was thinking of using the facade pattern but this would not be thread safe. Basically autowire the RequestContextHolder, and call setRequestContext each time a new context gets initialized.
#Component
#NoArgsConstructor
#Getter
#Setter
public class RequestContextHolder {
private RequestContext requestContext;
}
I'm not sure how your question:
Is there a way to autowire an object that needs to be re-instantiated frequently?
Is related to the use case that you've presented in the question...
From the question it looks like you can consider using ThreadLocals as a conceptual "substitution" to the global variable available all over the place in the request if you don't want to add parameters to the methods to propagate the context through the flow.
This will work only in "thread-per-request" model, it won't work for reactive systems and for the complicated cases where you maintain different thread pools and switch the threads while implementing the Business Logic on backend:
So to achieve "thread-safety" in your context holder that you have suggested you can use:
#Configuration
public class MyConfig {
#Bean
public ThreadLocal<MyCustomContext> ctxHolder() {
return new ThreadLocal<>();
}
}
Then, again, if you're working in thread-per-request model, you can:
#Component
public class DataFetcherInterceptor {
#Autowired
private ThreadLocal<MyCustomContext> ctxHolder;
public Result dataFetcher(DataFetchingEnvironment dfe) {
// this context contains user details which is used for authorization
// instantiated for every request
setRolesInContext(dfe);
MyCustomContext context = DgsContext.getCustomContext(dfe);
ctxHolder.set(context);
dataFetcherHelper();
}
}
In the dataFetcherHelper or in general in any method that requires the access to the context you can:
public class SomeService {
#Autowired ThreadLocal<MyCustomContext> ctxHolder;
public void dataFetcherHelper() {
MyCustomContext ctx = ctxHolder.get();
}
Now, I see that dataFetcherHelper is just a method that you call from withing this "interceptor" class, in this case its an overkill, but I assume, you've intended that this is actually a method that belongs to another class, that might be an element in the call-chain of different classes. For these situations, this can be a working solution.

Are these classes that I wrote broken in terms of thread-safety? Also, are ManagedBeans used in different Threads?

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.

Pitfalls for #Autowired and Threads

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.

How to make jsp spring application thread safe?

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.

Categories

Resources