We are using InheritableThreadLocal in a web application at request level to store an ApplicationContext object that is used throughout the application.
There is a scenario for an async response wherein the request creates an acknowledgement ID and launches a child thread and returns the acknowledgement ID back. Finally, the ThreadLocal is removed.
However, the child thread seems to lose the ApplicationContext (is null) if it is running longer than the time it takes for the request to be processed.
Pseudo code:
doPost() {
ApplicationContext ctx = createApplicationContext(req);
MyThreadLocalContainer.setContext(ctx);
new Thread(new RequestProcessor()).start(); // this seems to lose the ctx
MyThreadLocalContainer.removeContext();
}
Definition of MyThreadLocalContainer:
public class MyThreadLocalContainer {
private static final ThreadLocal<ApplicationContext> APP_CTX = new InheritableThreadLocal<ApplicationContext>();
public static void setContext(ApplicationContext ctx) {
APP_CTX.set(ctx);
}
public static void removeContext() {
APP_CTX.remove();
}
}
How can the ThreadLocal cleanup be handled in this scenario without having to wait for the child thread to complete before calling removeContext()?
Related
I have an autowired jpa repository object working. However, I need to use it to add rows into the database from multiple threads.
Though, after passing it to another thread, it fails.
Code structure
#SpringBootApplication(exclude = HealthcheckConfig.class)
public class Application implements CommandLineRunner {
#Autowired
private DBRepository dbRepository;
#Autowired
private AppConfig appConfig;
private ExecutorService executors = Executors.newFixedThreadPool(3);
Application() {
}
#Override
public void run(final String... args) {
final DBSchemaObject temp = new Application("testdb", "testfield");
dbRepository.save(temp); // This WORKs!!!
for (FileStatus fileStatus: fileStatuses) {
executors.execute(new ThreadSafeClass(dbRepository));
}
}
public static void main(final String[] args) {
new SpringApplicationBuilder(Application.class)
.web(WebApplicationType.NONE)
.run(args)
.close();
}
}
However, doing a dbRepository.save() from a thread safe class, I get error
cause: java.lang.IllegalStateException: org.springframework.context.annotation.AnnotationConfigApplicationContext#41330d4f has been closed already
detailedMessage: Error creating bean with name 'spring.datasource-org.springframework.boot.autoconfigure.jdbc.DataSourceProperties': Could not bind properties to 'DataSourceProperties' : prefix=spring.datasource, ignoreInvalidFields=false, ignoreUnknownFields=true
Stacktrace:
{StackTraceElement#14839} "org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800)"
{StackTraceElement#14840} "org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:229)"
{StackTraceElement#14841} "org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1354)"
{StackTraceElement#14842} "org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1204)"
{StackTraceElement#14843} "org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:564)"
{StackTraceElement#14844} "org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524)"
{StackTraceElement#14845} "org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)"
{StackTraceElement#14846} "org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)"
{StackTraceElement#14847} "org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)"
{StackTraceElement#14848} "org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)"
{StackTraceElement#14849} "org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:410)"
{StackTraceElement#14850} "org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1334)"
{StackTraceElement#14851} "org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1177)"
{StackTraceElement#14852} "org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:564)"
{StackTraceElement#14853} "org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524)"
{StackTraceElement#14854} "org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)"
{StackTraceElement#14855} "org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)"
{StackTraceElement#14856} "org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)"
{StackTraceElement#14857} "org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)"
{StackTraceElement#14858} "org.springframework.beans.factory.support.DefaultListableBeanFactory$1.orderedStream(DefaultListableBeanFactory.java:481)"
{StackTraceElement#14859} "org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.detectPersistenceExceptionTranslators(PersistenceExceptionTranslationInterceptor.java:167)"
{StackTraceElement#14860} "org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:149)"
{StackTraceElement#14861} "org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)"
{StackTraceElement#14862} "org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:174)"
{StackTraceElement#14863} "org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)"
{StackTraceElement#14864} "org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)"
{StackTraceElement#14865} "org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)"
{StackTraceElement#14866} "org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)"
{StackTraceElement#14867} "com.sun.proxy.$Proxy99.save(Unknown Source)"
{StackTraceElement#14868} "com.xxxx.run(Application.java:109)"
{StackTraceElement#14869} "java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)"
{StackTraceElement#14870} "java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)"
{StackTraceElement#14871} "java.lang.Thread.run(Thread.java:748)"
How can I use the spring boot repository object across multiple threads ?
The problem is that your run() method just schedules the tasks to be executed, but does not wait for their completion. This what is happening:
new SpringApplicationBuilder(Application.class) You are creating a new application context with the command line runner Application
.run(args) Then you initialize and execute your application context's run() method
The run() method schedules the tasks to be executed and exists immediately:
public void run(final String... args) {
for (FileStatus fileStatus: fileStatuses) {
executors.execute(new ThreadSafeClass(dbRepository));
}
}
Because run() terminated, spring assumes that the application has finished and calls .close(); Thus closing the application context and making it impossible to use any spring features such as repositories.
The scheduled tasks get executed, but the context was already closed, thus they fail and throw the exception.
The solution is to wait for the tasks' completion before exiting from the run method. As your example is too minimal, this is just an example. Alternatively you can use other methods to wait for the completion of the tasks such as CountDownLatch , etc, without having to shutdown the thread pool:
for (FileStatus fileStatus: fileStatuses) {
executors.execute(new ThreadSafeClass(dbRepository));
}
executors.shutdown(); // prevents the executor from accepting any new tasks
executors.awaitTermination(); // wait for the tasks to finish
ExecutorService::shutdown javadoc
ExecutorService::awaitTermination javadoc
I have a class say MessageListener class. That has a method startListening() which listens on the Multicast IP and Port to receive message in an infinite loop:
public class MainClass {
public static void main(String args[]) {
MessageListener listener = new MessageListener();
listener.startListening(); // Started ONLY ONce for the entire application
}
}
public class MessageListener implements MessageReceiver{
public void startListening(MessageReceiver receiver) {
new Thread("Worker thread") {
#Override
public void run() {
// TODO Auto-generated method stub
while(true) {
//MulticastSocket receive - receives byte[]
messageReceived(byte[]);
}
}}).start();
}
public void messageReceived(byte[] data) { // Interface Method
new Message().handleMessage(data);
}
}
public class Message() {
MessageHeader messageHeader;
MessageBody messageBody;
public void handleMessage(byte[] data) {
messageHeader = new MessageHeader();
messageHeader.parseHeader(data); //subsequent messages interleave the thread here?
//extract msgbody from data
messageBody = new MessageBody();
messageBody.parseMessageBody(); //subsequent messages interleave the thread here?
}
}
I have above structure of classes. startListening() is called ONLY once at the start of the application. My assumption is the startListening() creates ONE worker thread (for the entire app) in addition to main thread and all the methods messageReceived(), handleMessage(), parseHeader(), and parseMessageBody() are all called in this one worker thread and hence these methods are entirely running in single worker thread and when new message arrives from the MulticastSocket, the methods starting from messageReceived() should run sequentially like a single threaded application.
But the method access is interleaving between the incoming messages. Say for instance, while first message is accessing parseHeader(), second message also accesses parseHeader().
I could not sync everything into like one single worker thread access unless I make the method calls as “static synchronised” to make it lock on the class instance otherwise with object synchronisation, obviously the message would be having independent access with different objects.
Is there a way I can make this work like a Single worker thread access for one message till it completes or make the method access sequentially between methods without static synchronized method modifiers?
I have a #RabbitListener and properly working consuming from queue.
In my listener I set context.
I know that there are many (configurable) threads consuming the same queue (so in real executing the same lisener code).
Now, I consdier when is good time to clear context ?
To be more precisely, it is problem for me to express:
"When you end consuming (no matter with exception or not) do clear context)"
Below, you can see a scheme of my problem:
public class CustomContextHolder {
private static final ThreadLocal<DatabaseType> contextHolder =
new ThreadLocal<DatabaseType>();
public static void setContext(DatabaseType databaseType) {
contextHolder.set(databaseType);
}
public static CustomerType getContext() {
return (CustomerType) contextHolder.get();
}
public static void clearContext() {
contextHolder.remove();
}
}
#RabbitListener
void listenMessage(Message message) {
...
CustomContextHolder.set(...);
}
It's generally better to use stateless objects as listeners rather than using ThreadLocal.
However, if you are forced to keep state this way, you can implement ApplicationListener<AmqpEvent>.
The ApplicationListener will receive several events; specifically, the AsyncConsumerStoppedEvent when the consumer is stopped normally and ListenerContainerConsumerFailedEvent if the consumer stops abnormally. These two events are published on the listener thread, so you can clear your ThreadLocal there.
Other events may or may not be published on the listener thread.
I've got an ExecutorService sitting inside a singleton class which receives tasks from many different classes. On application shutdown, I need to wait for the pool to be empty before I allow the application to exit.
private static NotificationService instance = null;
private ExecutorService executorService = Executors.newFixedThreadPool(25);
public static synchronized NotificationService getInstance() {
if (instance == null) {
instance = new NotificationService(true);
}
return instance;
}
While using this NotificationService, it frequently happens that I restart the application and the executorService hasn't finished processing all the notifications.
For Testing, I can manually shutdown the executorService and wait until all tasks are completed.
public static boolean canExit() throws InterruptedException {
NotificationService service = getInstance();
service.executorService.shutdown();
service.executorService.awaitTermination(30, TimeUnit.SECONDS);
return service.executorService.isTerminated();
}
Is it reliable and safe to override the finalize method and wait there until the pool is empty? From what I've read, finalize is not always called, especially not when using a singleton class.
#Override
protected void finalize() throws Throwable {
while (!canExit()){
Thread.sleep(100);
}
super.finalize();
}
This code is included in a library that will be included in another application, so there's no main method where I can wait until the pool is empty, unless I force the person using it to do so which is not great.
What is the correct way to stall the application (for a reasonable amount of time) from terminating until the pool is empty?
You can use addShutdownHook to catch the process termination event and wait for the pool there.
example:
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
NotificationService service = getInstance();
service.executorService.shutdown();
service.executorService.awaitTermination(30, TimeUnit.SECONDS);
}
});
Answered here: Java Finalize method call when close the application
Finalizers do not run on exit by default and the functionality to do this is deprecated.
One common advice is to use the Runtime.addShutdownHook but be aware of the following line of documentation:
Shutdown hooks should also finish their work quickly. When a program invokes exit the expectation is that the virtual machine will promptly shut down and exit. When the virtual machine is terminated due to user logoff or system shutdown the underlying operating system may only allow a fixed amount of time in which to shut down and exit. It is therefore inadvisable to attempt any user interaction or to perform a long-running computation in a shutdown hook.
In all honesty the best way to ensure everything gets properly cleaned up is to have your own application lifecycle which you can end before you even ask the VM to exit.
Don't use blocking shutdown hooks or anything similar in a library. You never know how the library is meant to be used. So it should always be up to the code that is using your library to take sensible actions on shut down.
Of course, you have to provide the necessary API for that, e.g. by adding lifecycle-methods to your class:
public class NotificationService {
...
public void start() {
...
}
/**
* Stops this notification service and waits until
* all notifications have been processed, or a timeout occurs.
* #return the list of unprocessed notification (in case of a timeout),
or an empty list.
*/
public List<Notification> stop(long timeout, TimeUnit unit) {
service.shutdown();
if (!service.awaitTermination(timeout, unit)) {
List<Runnable> tasks = service.shutdownNow();
return extractNotification(tasks);
}
return Collections.emptyList();
}
private List<Notification> extractNotification(List<Runnable> tasks) {
...
}
}
Then, the application code can take the required actions to handle your service, e.g.:
public static void main(String[] args) {
NotificationService service = new NotificationService(...);
service.start();
try {
// use service here
} finally {
List<Notification> pending = service.stop(30, TimeUnit.SECONDS);
if (!pending.isEmpty()) {
// timeout occured => handle pending notifications
}
}
}
Btw.: Avoid using singletons, if feasible.
I have a web application running in tomcat where I'm using a ThreadPool (Java 5 ExecutorService) to run IO intensive operations in parallel to improve performance. I would like to have some of the beans used within each pooled thread be in the request scope, but the Threads in the ThreadPool do not have access to the spring context and get a proxy failure. Any ideas on how to make the spring context available to the threads in the ThreadPool to resolve the proxy failures?
I'm guessing there must be a way to register/unregister each thread in the ThreadPool with spring for each task, but haven't had any luck finding how to do this.
Thanks!
I am using the following super class for my tasks that need to have access to request scope. Basically you can just extend it and implement your logic in onRun() method.
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
/**
* #author Eugene Kuleshov
*/
public abstract class RequestAwareRunnable implements Runnable {
private final RequestAttributes requestAttributes;
private Thread thread;
public RequestAwareRunnable() {
this.requestAttributes = RequestContextHolder.getRequestAttributes();
this.thread = Thread.currentThread();
}
public void run() {
try {
RequestContextHolder.setRequestAttributes(requestAttributes);
onRun();
} finally {
if (Thread.currentThread() != thread) {
RequestContextHolder.resetRequestAttributes();
}
thread = null;
}
}
protected abstract void onRun();
}
I also wish I had 1000 votes to give to the currently accepted answer. I had been stumped on how to do this for some time. Based on it, here is my solution using the Callable interface in case you want to use some of the new #Async stuff in Spring 3.0.
public abstract class RequestContextAwareCallable<V> implements Callable<V> {
private final RequestAttributes requestAttributes;
private Thread thread;
public RequestContextAwareCallable() {
this.requestAttributes = RequestContextHolder.getRequestAttributes();
this.thread = Thread.currentThread();
}
public V call() throws Exception {
try {
RequestContextHolder.setRequestAttributes(requestAttributes);
return onCall();
} finally {
if (Thread.currentThread() != thread) {
RequestContextHolder.resetRequestAttributes();
}
thread = null;
}
}
public abstract V onCall() throws Exception;
}
Could you try it the other way round? Use a data container that's stored in request scope and give it to the thread pool (perhaps put it into a queue, so that the thread pool can take one data container at a time, work on it, mark it as "done" and continue with the next one).
Spring has a ThreadPoolTaskExecutor class that you can use to manage your thread pool from Spring. However, it looks like you'd have to do some work to make the Spring context available to each thread.
I'm not sure if it will work even if you do wire it up this way though. Spring uses a token in thread local to locate objects in request (or session) scope, so if you're trying to access a request scope bean from a different thread, it's likely that token won't be there.