I've written some code that essentially is responsible for orchestrating a number of API's in sequence through a library method I provide to my clients called "orchestrate" (yes I know so original). What sits behind this orchestrate method is nothing more than a loop that executes API's in the order they are received, which in turn are delegated to a number of classes that contain some business logic for building a request, calling an API, performing some validation on the response and finally returning the api result. So, if a client sent in a list of apis:
{a1, a2, a3, a4, a5} it would execute each api in sequence in a completely blocking way.
I'm attempting to beef this up to where I'm able to call multiple API's in parallel depending on how I receive the instructions from a client. Think of it as the client sending me a list of lists like: { {a1, a2}, {a3}, {a4, a5} }
This means I'd like to execute a1 and a2 in parallel (which means build their request, call the apis, validate the response). Then wait until i'm sure both of them are done. Then execute a3, and wait until i'm sure it's done. Finally I want to execute a4 and a5 and follow the usual pattern.
Now, I'm tempted to use futures for the simple abstraction they provide to execute methods a wait for the response using the .get() method. But what I noticed that the executorService needs underneath is future's invocation of a call() method. This is fine, but makes me think that the call() method that is implemented per class may need access to "local" data in order to do its job (after all, I can't pass the call() method any particular parameters). I really want to avoid holding any local mutable state because that brings its own side-effects.
Is there a way for me to NOT hold local state and still use futures to handle my multithreading use-case? Or is my understanding of futures completely wrong and I'm missing something obvious? If not, are there any recommendations on a good path forward with some alternatives?
OK, so you have a class which gets you some data from a web page in a blocking way, and takes some arguments:
public class DataFetcher {
public Data fetchData(int param1, int param2) {
// ...
}
}
And now you want to execute this method twice, concurrently, and get back futures. So you just need to create a Callable:
final DataFetcher fetcher = new DataFetcher();
Callable<Data> task1 = new Callable<>() {
#Override
public Data call() {
return fetcher.fetchData(1, 2);
}
};
Callable<Data> task2 = new Callable<>() {
#Override
public Data call() {
return fetcher.fetchData(3, 4);
}
};
Future<Data> result1 = executorService.submit(task1);
Future<Data> result2 = executorService.submit(task2);
I don't see any mutable state here.
To avoid repeating the code and using anonymous classes, you can define a top-level class:
public DataFetcherTask implements Callable<Data> {
private final DataFetcher fetcher;
private final int param1;
private final int param2;
public DataFetcherTask(DataFetcher fetcher, int p1, int p1) {
this.fetcher = fetcher;
this.param1 = p1;
this.param2 = p2;
}
#Override
public Data call() {
return fetcher.fetchData(param1, param2);
}
};
and then use it like this:
Future<Data> result1 = executorService.submit(new DataFetcherTask(fetcher, 1, 2));
Future<Data> result2 = executorService.submit(new DataFetcherTask(fetcher, 3, 4));
Still no trace of mutable state here.
Related
For a given request like /api/user/1, suppose it will take 10s for querying from db.
So at first there is one request accepted by the server, and the service start to query the db. Then during the query, there maybe some more incoming same requests(all for /api/user/1).
How to avoid the later requests query the database? We do not mean cache, we just want to avoid the exactly same query occur at the same time.
Is this make any sense? If yes, how to you make that (Take Java or node application as example)?
You could use a ConcurrentHashMap (see here) which maps route strings like "/api/user/1" to a List of callbacks taking a single parameter of type T (replace T with whatever class you use to store request results). Your request method will need to use a Consumer<T> for the callback. If you are not familiar with Consumer<T> you can read about it here. It is simply an interface representing a function which takes one parameter of type T and which returns nothing.
When a thread wants the result of the request to a route it should call a synchronized method register which takes a route as a String and a callback and does the following:
It should check if the route is a key in the Map. If it isn't, it should add the route as a key to the Map with its value being a List containing one value, the callback supplied in the parameter, and then it should initiate the request with a callback to a method resolve which I will discuss below. If the route was already a key in the Map then the callback of the thread should simply be added to the List in the Map where the route is the key.
The resolve function should take the route as a String and the request result of type T. It should then get the List at the route key, remove the route key from Map, and finally iterate over all of the callbacks and call them with the request result.
I have written up some code with an example, but I have not tested it.
CallbackHandler.java
public abstract class CallbackHandler<T> {
private QueryRepetitionHandler<T> handler;
private CountDownLatch latch;
private T result;
public CallbackHandler(QueryRepetitionHandler<T> handler) {
this.handler = handler;
latch = new CountDownLatch(1);
}
public void resolve(T result) {
this.result = result;
latch.countDown();
}
public void request(String route) {
handler.register(route);
latch.await();
}
}
QueryRepetitionHandler.java
public abstract class QueryRepetitionHandler<T> {
private Map<String, List<CallbackHandler<T>> map = new ConcurrentHashMap<>();
protected abstract void request(String route, Consumer<T> consumer);
public synchronized void register(String route, CallbackHandler<T> handler) {
if (map.containsKey(route)) {
map.get(route).add(callback);
} else {
List<CallbackHandler<T>> list = new ArrayList<>();
list.add(callback);
map.put(route, list);
request(route, result -> resolve(route, result));
}
}
private void resolve(String route, T result) {
List<Consumer<T>> list = map.remove(route);
// Sanity check
if (list != null) {
list.forEach(handler -> handler.resolve(result));
}
}
}
You'll want to instantiate one QueryRepetitionHandler<T> to be shared by all of your threads. When a thread wants to make a request it should instantiate a CallbackHandler<T> using the shared QueryRepetitionHandler<T>. Of course, you can't instantiate QueryRepetitionHandler<T> without implementing the request method. The request method should simply make the request and then call the callback provided as a Consumer<T>. It should then call the request method of CallbackHandler<T> with the desired route as a String argument. That thread will then be waiting (using latch.await()) for the result of the request until QueryRepetitionHandler<T> calls its resolve method with the result and calls latch.countDown().
Say I have two heavyweight IO blocking operations, findMatchInSomeDB() and getDetailsFromOtherDB(String objectKey). Furthermore, I want them to run in the background, and use Guava Futures to chain them together because one depends on the result of the other (I know this could just be done sequentially in a simple Callable, but keeping it simple for illustration purposes):
Is there any practical or nuanced difference between the consumeChain and consumeChainAsync methods below?
import com.google.common.base.Function;
import com.google.common.util.concurrent.AsyncFunction;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
public class Consumer
{
private final Retriever retriever;
private final ListeningExecutorService executorSvc;
public Consumer(Retriever retriever, ListeningExecutorService executorSvc)
{
this.retriever = retriever;
this.executorSvc = executorSvc;
}
private void consumeChain(String searchCriteria) throws Exception
{
ListenableFuture<String> futureMatch = executorSvc.submit(
() -> retriever.findMatchInSomeDB(searchCriteria));
Function<String, DataObject> keyToDataObj = objectKey ->
retriever.getDetailsFromOtherDB(objectKey);
// using "real" executor service so transform function runs
// in the background
ListenableFuture<DataObject> futureDataObj = Futures.transform(
futureMatch, keyToDataObj, executorSvc);
// ...do some other stuff in this thread...
// do something with futureDataObj result
futureDataObj.get();
}
private void consumeChainAsync(String searchCriteria) throws Exception
{
ListenableFuture<String> futureMatch = executorSvc.submit(
() -> retriever.findMatchInSomeDB(searchCriteria));
AsyncFunction<String, DataObject> keyToDataObj = objectKey ->
{
return executorSvc.submit(
() -> retriever.getDetailsFromOtherDB(objectKey));
};
// using DirectExecutor because the transform function
// only creates and submits a Callable
ListenableFuture<DataObject> futureDataObj = Futures.transformAsync(
futureMatch, keyToDataObj, MoreExecutors.directExecutor());
// ...do some other stuff in this thread...
// do something with futureDataObj
futureDataObj.get();
}
}
As far as I can tell, both will run each heavyweight operation via executorSvc, and both will propagate cancellation and/or execution failure.
It seems that the only point of transformAsync (instead of just using transform with an executor other than DirectExecutor) is for when you're working with an API that returns ListenableFuture instead of directly running the operation. Am I missing something?
It seems that the only point of transformAsync (instead of just using transform with an executor other than DirectExecutor) is for when you're working with an API that returns ListenableFuture instead of directly running the operation.
I think that's the idea.
However, I can think of a small difference that makes transformAsync slightly better: If you call cancel(true) on the output Future, transform currently won't interrupt the thread that runs getDetailsFromOtherDB. In contrast, transformAsync will (by calling cancel(true) on the ListenableFuture returned from the ListeningExecutorService). transform should propagate interruption, but there are some subtleties to getting this right, covered in the link above.
I use a method for more than one time in JavaScript by using callback method because JavaScript is an async language.
Example:
function missionOne () {
sumCalculation(1, 2, function (result) {
console.log(result) // writes 3
})
}
function sumCalculation (param1, param2, callback) {
let result = param1 + param2
// The things that take long time can be done here
callback(result)
}
I wonder if there is any way to stop myself in Java?
Edit: I remove several sentences that make more complex the question.
I may be reading too much into your question, but it seems that you're looking into how to handle asynchronous code in Android. There are a couple of native options (not considering any library). I'll focus on two, but keep in mind there are other options.
AsyncTasks
From the documentation
AsyncTask enables proper and easy use of the UI thread. This class allows you to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
Before writing one, you need to know which type of parameters it will receive, the type of progress it will publish during computation and what is its return type. These types are define via the AsyncTask generic Parameters AsyncTask<Params,Progress,Result>. If you don't need them any of them, set them to Void
Here's the basic gist of using an AsyncTask to compute the sum of two ints:
public void sumCalculation (int param1, int param2, Callback callback) {
new AsyncTask<Integer, Void, Integer>() {
#Override
public Integer doInBackground(Integer... params) {
int result = 0;
for (Integer param : params) {
result += param;
}
return result;
}
#Override
protected void onPostExecute(Integer integer) {
super.onPostExecute(integer);
callback.onDone(integer);
}
}.execute(param1, param2);
}
doInBackground, as the name says, will execute a certain piece of code in a background thread. Please note that every AsyncTask will run on a ThreadPool of size 1, so they actually get in the way of other AsyncTasks.
onPostExecute brings the result back to the main thread, so you can update any UI componente. If you try to update the UI from a background thread, an exception will be thrown.
The down side of this particular example is the creation of a new AsyncTask every time that function is called.
Also you should use AsyncTask only if the task won't run for a very long time, couple of seconds at most.
Thread and Handler
Another option suggested on the documentation is using a thread and a handler to communicate between the main thread and a background thread. Although this provides greater flexibility, it also requires more responsibility as you will be responsible for managing the communication yourself, picking the right time to kill your threads and how to recover when something goes bad.
As a rule of thumb, you should only go this way if you really need the extra flexibility.
The overall idea is to create your own Handler and override its handleMessage method.
public class MyHandler {
#Override
public void handleMessage(Message inputMessage) {
int messageType = inputMessage.what;
Object extraData = inputMessage.obj;
...
}
}
public class MyTask extends Thread {
public static public int COMPUTATION_DONE = 0;
private MyHandler handler;
public MyTask(MyHandler handler) {
this.handler = handler;
}
#Override
public void run() {
//do your computation
Message message = handler.obtainMessage(COMPUTATION_DONE, your_result);
handler.sendMessage(message);
}
}
As you can see, this requiring parsing inputMessage.what and deciding what to do with it. Additionally, you need to cast inputMessage.obj to the right type and so on.
These are just two examples, but depending on what you're trying to do, you might need to dig deeper into Services or take a look at some reactive approach, such as RxJava2. However I encourage you to start with the basic before diving into something way more complicated.
Yes it is easy in Java. To take your example above you can write it in Java like this:
public static void main(String[] args) {
System.out.println(sumCalc(1,2));
}
private int sumCalc(int first, int second) {
return first + second;
}
I want to read a message at a specific position in an class other than InboundHandler. I can't find a way to read it expect in the channelRead0 method, which is called from the netty framework.
For example:
context.writeMessage("message");
String msg = context.readMessage;
If this is not possible, how can I map a result, which I get in the channelRead0 method to a specific call I made in another class?
The Netty framework is designed to be asynchronously driven. Using this analogy, it can handle large amount of connections with minimal threading usage. I you are creating an api that uses the netty framework to dispatch calls to a remote location, you should use the same analogy for your calls.
Instead of making your api return the value direct, make it return a Future<?> or a Promise<?>. There are different ways of implementing this system in your application, the simplest way is creating a custom handler that maps the incoming requests to the Promises in a FIFO queue.
An example of this could be the following:
This is heavily based on this answer that I submitted in the past.
We start with out handler that maps the requests to requests in our pipeline:
public class MyLastHandler extends SimpleInboundHandler<String> {
private final SynchronousQueue<Promise<String>> queue;
public MyLastHandler (SynchronousQueue<Promise<String>> queue) {
super();
this.queue = queue;
}
// The following is called messageReceived(ChannelHandlerContext, String) in 5.0.
#Override
public void channelRead0(ChannelHandlerContext ctx, String msg) {
this.queue.remove().setSuccss(msg);
// Or setFailure(Throwable)
}
}
We then need to have a method of sending the commands to a remote server:
Channel channel = ....;
SynchronousQueue<Promise<String>> queue = ....;
public Future<String> sendCommandAsync(String command) {
return sendCommandAsync(command, new DefaultPromise<>());
}
public Future<String> sendCommandAsync(String command, Promise<String> promise) {
synchronized(channel) {
queue.offer(promise);
channel.write(command);
}
channel.flush();
}
After we have done our methods, we need a way to call it:
sendCommandAsync("USER anonymous",
new DefaultPromise<>().addListener(
(Future<String> f) -> {
String response = f.get();
if (response.startWidth("331")) {
// do something
}
// etc
}
)
);
If the called would like to use our a api as a blocking call, he can also do that:
String response = sendCommandAsync("USER anonymous").get();
if (response.startWidth("331")) {
// do something
}
// etc
Notice that Future.get() can throw an InterruptedException if the Thread state is interrupted, unlike a socket read operation, who can only be cancelled by some interaction on the socket. This exception should not be a problem in the FutureListener.
I read answers from similar Q&A
How do you create an asynchronous HTTP request in JAVA? |
Asynchronous programming design pattern |
AsyncTask Android - Design Pattern and Return Values
I see a lot of solutions , but none really satifies me.
Listener way
Once the results are caught, the processing is implemented in onResult method.
public interface GeolocationListener {
public void onResult(Address[] addresses);
public void onError(Exception e);
}
This solution doesn't quite satify me , because I want to handle the results in the main method. I hate this interface because when the response is returned, it is processed in onResult resulting in chains of processing and no way to go back to the "main" method.
The servlet way
public class SignGuestbookServlet extends HttpServlet {
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
// ...
resp.sendRedirect("/guestbook.jsp");
}
}
There is no exposed Java code calling the servlet. All the configuration is done in the web.xml
The way I want
Wait for the response like this
Response a = getResponse();
// wait until the response is received, do not go further
// process
Response b = getResponse();
// wait until the response is received, do not go further
process(a,b);
Is there a design pattern to handle the async request and wait for the response like above ? Other way than the listener.
Please no library or framework.
EDIT
Thanks so far the responses. I didn't give you the full picture so I exposed the Geolocation class
I started the implementation . I don't know how to implement the method . Can someone shows "how to" ? He (or she) must also implement the listener to retrieve the results
private Address getFullAddress (String text, AddressListener listener, ... ){
// new Geolocation(text, listener, options).start()
// implements Geolocation.GeolocationListener
// how to return the Address from the onResult ?
}
First, you should not reject the first two methods you discuss. There are very good reasons people are using those techniques and you should try to learn them instead of creating new ones.
Otherwise, you should look at java.util.concurrent:
ExecutorService es = Executors.newFixedThreadPool(2);
...
Future<Response> responseA = es.submit(responseGetter);
Future<Response> responseB = es.submit(responseGetter);
process(responseA.get(), responseB.get());
where responseGetter is of type Callable<Response> (you must implement the method public Response call()).
Asynchronous code can always be made synchronous. The simplest/crudest way is to make the async call, then enter a while loop that just sleeps the current thread until the value comes back.
Edit: Code that turns an asynchronous callback into synchronous code--again, a crude implementation:
import java.util.concurrent.*;
public class MakeAsynchronousCodeSynchronous {
public static void main(String[] args) throws Exception {
final Listener listener = new Listener();
Runnable delayedTask = new Runnable() {
#Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
throw new IllegalStateException("Shouldn't be interrupted", e);
}
listener.onResult(123);
}
};
System.out.println(System.currentTimeMillis() + ": Starting task");
Executors.newSingleThreadExecutor().submit(delayedTask);
System.out.println(System.currentTimeMillis() + ": Waiting for task to finish");
while (!listener.isDone()) {
Thread.sleep(100);
}
System.out.println(System.currentTimeMillis() + ": Task finished; result=" + listener.getResult());
}
private static class Listener {
private Integer result;
private boolean done;
public void onResult(Integer result) {
this.result = result;
this.done = true;
}
public boolean isDone() {
return done;
}
public Integer getResult() {
return result;
}
}
}
You could also use a CountDownLatch as recommended by hakon's answer. It will do basically the same thing. I would also suggest you get familiar with the java.util.concurrent package for a better way to manage threads. Finally, just because you can do this doesn't make it a good idea. If you're working with a framework that's based on asynchronous callbacks, you're probably much better off learning how to use the framework effectively than trying to subvert it.
Could CountDownLatch help you? In the main method, you call getResponse and then countDownLatch.await(). Pass a count down latch to the getResponse method and then count down once getResponse the result from getResponse is finished:
CountDownLatch latch = new CountDownLatch(1);
Response a = getResponse(latch);
latch.await();
latch = new CountDownLatch(1);
Response b = getResponse(latch);
latch.await();
process(a, b);
Your getResponse needs to call latch.countDown() once it's asynch parts return a result.
e.g.:
public Response getResponse(CountDownLatch latch) {
someAsychBloc(final CountDownLatch latch) {
do work
latch.countDown();
}
}
Essentially you need a "listener" of sorts no matter what. This is because you do not know WHEN your return message will come back, if at all (that is one of the downsides of asynchronous processing...what to do if you do not get a return message).
So you either need to implement a listener that waits for events (ie, it is nudged by the returning message to be processed).
Or you could do a hybrid on that by having a separate thread that "polls" (or pulls) a response area on your service to see if the return message exists.
So it really comes down to whether you want more of a "pull" or "push" method of retrieving messages.
The SCA (Service Component Architecture) framework might be something to consider, but depending on what you are doing, it could be overkill too. But something to consider.
EDIT:
I just found this in the Java SE 6 Javadocs that may be helpful. The
interface CompletionService which abstracts the very thing you care
about --> asynchronous work. I suggest you take a look.
If you want a page flow in a web application, you have to handle in the web way : storing some data either in the session, or cookies or hidden fields, etc.
The problem you're trying to tackle, as far as I understand it, doesn't come from asynchronousness but from the stateless http protocole.
Regards,
Stéphane