I'm trying to create an architecture using Java Spring which will have several background processes which will be running concurrently, listening and pulling information as it arrives from different ZMQ sockets.
I'm not sure the best way to do this. Right now, i'm using the #Async annotation with a TaskPoolExecutor, but the #Async function seems to be blocking the next function call in the stack.
So my questions are
1) Will an #Async function block the next function call in the stack? Or will it fire off that function in a new thread, and continue executing the functions in the current thread.
2) Is there any way to give each Thread an equal timeslice of computing power.
3) Are there any better ways to do this?
Thanks!
#Async will run the annotated method asynchronously using the
specified executor.
There is no way to control OS resources
dedicated to threads.
Java has a very convenient
CompletableFuture API for asynchronous computations. I've
recently wrote a blog post about the problems with #Async and how
they can be solved with CompletableFuture: Demystifying the Magic
of Spring: #Async .
Related
I need to update 3 data regions by making a synchronous call to one data region and asynchronous call to other 2 data regions using Java n spring.which is the best way to implement this?
Apart from the term region I understood you want to make a few http requests. One of them (the first) has to be blocking.
I would suggest you to have a look into spring's WebClient which let you make multiple requests in parallel.
The first (blocking) one can be achieved by a blocking Mono.
Here you can find a tutorial on Simultaneous Spring WebClient Calls:
https://www.baeldung.com/spring-webclient-simultaneous-calls
Cheers
I am developing a Service that calls multiple external services that are independent of each other. I collate the responses of all these services and return it as a consolidated response. Since these are not interdependent , I am using Spring's #Async capability to perform all these activities in parallel. I am following the example provided in this link
https://spring.io/guides/gs/async-method/
Here , a while loop is used to wait until all the responses are obtained -
while (!(page1.isDone() && page2.isDone() && page3.isDone())) {
Thread.sleep(10); //10-millisecond pause between each check
}
I know this a sample code which was aimed at explaining the concept, which it does effectively. However in an enterprise application , can a while loop be used similar to what is shown above or should a different approach be adopted? If a different approach has to be adopted what is the advantage of the approach over using a while loop?
Couldn't you just use Future.get()? It's a blocking call. It'll make sure to wait until the result is ready. You can do something like:
List<Future<?>> results = Lists.newArrayList();
results.add(page1.get());
results.add(page2.get());
results.add(page3.get());
My Data Model is based on time series(inserts feeds from various sources in cassandra CFs.) Can anyone suggest how to do inserts in Multi Threading.? Is executing query with executeAsync method similar to multi threading ? Is there any property of cassandra.yaml which I need to set to achieve Multi Threading ? Or any other prerequisites.
The driver is safe for multi-threaded use. What you will typically do is build your Cluster and get a Session instance during application startup, and then share the Session among all threads.
How you handle multi-threading is specific to your code. I don't know SQS either, but I imagine you'd either have multiple consumers that poll from the queue and process the messages themselves, or maybe dispatch the messages to a pool of workers.
Regarding executeAsync, the returned ResultSetFuture implements Guava's ListenableFuture, so you can register a success callback with addListener. But you'll have to provide an Executor to run that callback on (I don't recommend MoreExecutors#sameThreadExecutor as mentioned in the Javadoc, because your callback would end up running on one of the driver's I/O threads).
As mentioned by Carlo, a simple approach is to use the synchronous execute, and have your worker block until it gets a response from Cassandra, and then acknowledge the message.
executeAsync() creates a separate thread for the execution of the statement and immediately returns the control to caller -- a Future<ResultSet> will have your result. When working with this approach you won't know if any exception occurred until you're inside the Future.
In Cassandra you don't have to set anything. Just keep under control the thread-number within your application and initialize properly the Java Driver providing a PoolingOptions object that match your needs.
HTH, Carlo
If you are executing the query in multithreading environment, then make sure you wait for the executeAsync(statement) to complete,
session.executeAsync(statement) will return immediately, it does not guarantee whether the query is valid or submitted successfully. So if you're using threadpool then always use
ResultSetFuture future = session.executeAsync(statement);
future.getUninterruptibly();
This will wait for the query to be submitted and will not consume memory.
I have a spring bean with 4 blocking queues. Each queue is assigned a method (named processQueueX() ) which calls take() on that queue and processes taken object from queue.
I want to call each of those method in a separate thread on app startup.
I tried with task scheduler and fixed-delay setting but that in some way blocks tomcat and it stops responding to requests. Each method needs to be called once, so scheduling was a bad idea I guess.
Init method does not work also since it works in a single thread, each method has endless loop to process queue forever.
Is there a way to call these methods declaratively from spring config file in manner similar to task namespace? Or programmatically?
Tnx
I think using scheduler not a bad idea use quart scheduler with simple trigger thus quarz will do threading for you and tomcat not effected .And configure quartz with just enough number of thread.
Would 23.4. The Spring TaskExecutor abstraction help?
Where the example has a MessagePrinterTask class, you would have similar, but your run() method would access one of the queues. You would set up your Spring config to inject one of the queues into the task, so depending on how similar your queues are, you might be able to use the same Runnable task.
in a Spring MVC Controller I would like to start a thread that continues work while my controller sends the response. Will this work with spring-mvc ?
Best Reagrds,
Heinrich
Yes, You can start new Thread in Controller. But better way of doing asynchronous job is to use spring-scheduling support. You can leverage Quartz framework. That will manage your job.
This link will give you how to integrate this in your application.
Yes, it'll work. On one web app I worked on, I needed to send a notification email depending on the user's action. I added a post-commit interceptor on the service, and had that fire off the email in a separate thread. (In my case that happened to be cleaner than putting the code in the controller, because I only wanted it to happen if the transaction committed.)
You do need to make sure the thread actually stops running at some point, either by setting daemon to true (if it's ok that stopping the server kills the thread without notice) or making sure the code in its run method will always terminate at some point.
You are better off using a threadpool than creating new threads, so you don't risk resource exhaustion (threads stalling out are usually not independent events, if a thread hangs the next one probably will too, so you need a way to cut your losses). Methods annotated with #Async will be executed using an executor that you can configure as shown in the Spring documentation.
As the others mentioned, it's will work. ExecutorService can do the job. Here you can see I used it for starting a video stream that sits on a separate endpoint.
#PostMapping("/capture")
public ResponseEntity capture() {
// some code omitted
ExecutorService service = Executors.newCachedThreadPool();
service.submit(() -> startStreaming(deviceConfig));
return return ResponseEntity.ok()
.body(stream);
}