Executing Java callback on a new thread - java

On this project, a Manager performs event queuing, and to return the result of the event a callback is used (the callback does not extend Runnable). The manager runs on a separate thread, dispatching the events. Once the events terminate, this same thread calls the callbacks. This means that the next event will not be dispatched before the callback of the previous event terminates. In order to avoid this, I though about having the manager create a new thread for each callback, and executing the callbacks there. How good is this solution in terms of design practices, and is there a better way to achieve this?

A simple Callback code:
import java.util.concurrent.*;
import java.util.*;
public class CallBackDemo{
public CallBackDemo(){
System.out.println("creating service");
ExecutorService service = Executors.newFixedThreadPool(10);
try{
for ( int i=0; i<10; i++){
Callback callback = new Callback(i+1);
MyCallable myCallable = new MyCallable((long)i+1,callback);
Future<Long> future = service.submit(myCallable);
//System.out.println("future status:"+future.get()+":"+future.isDone());
}
}catch(Exception err){
err.printStackTrace();
}
service.shutdown();
}
public static void main(String args[]){
CallBackDemo demo = new CallBackDemo();
}
}
class MyCallable implements Callable<Long>{
Long id = 0L;
Callback callback;
public MyCallable(Long val,Callback obj){
this.id = val;
this.callback = obj;
}
public Long call(){
//Add your business logic
System.out.println("Callable:"+id+":"+Thread.currentThread().getName());
callback.callbackMethod();
return id;
}
}
class Callback {
private int i;
public Callback(int i){
this.i = i;
}
public void callbackMethod(){
System.out.println("Call back:"+i);
// Add your business logic
}
}
output:
creating service
Callable:1:pool-1-thread-1
Call back:1
Callable:2:pool-1-thread-2
Call back:2
Callable:8:pool-1-thread-8
Call back:8
Callable:3:pool-1-thread-3
Call back:3
Callable:10:pool-1-thread-10
Callable:4:pool-1-thread-4
Call back:10
Callable:7:pool-1-thread-7
Call back:7
Callable:6:pool-1-thread-6
Call back:6
Callable:9:pool-1-thread-9
Callable:5:pool-1-thread-5
Call back:9
Call back:4
Call back:5
Summary:
Replace Manager with ExecutorService of your preferred choice.
Either your can pass Callaback object to Callable/Runnable object Or you can create Callback object inside Callable/Runnable. In my example, I have explicitly passed Callback object to Callable.
Before returning the result, Callable object invokes Callback method. If you want to block on proceeding further unless you get response from current event, just uncomment below line.
System.out.println("future status:"+future.get()+":"+future.isDone());
I think you are going to avoid it and hence keep above line commented. You don't have to create new thread for Callback method invocation. If you want to process Callback event asynchronously, you can create one more ExecutorService and submit the event.

I would have the thread which executes the task, also execute the call back. Instead of creating a Thread each time, I suggest you use an ExecutorService.
public static <T> void submit(ExecutorService service,
Callable<T> callable,
Consumer<T> callback) {
service.submit(() -> {
try {
callback.accept(callable.call());
} catch (Throwable t) {
// log the Throwable
}
});
}

Related

Get first available AsyncResult

I have several async methods (Annotatad #Asynchronous) Returning Future Objects. I have to execute them at once but it would be enough for me to get the result of the first one which ready, is there any nice and safe solutions for that that works on a Java EE container?
Thanks!
There's no standard API for this facility. Just check Future#isDone() yourself in an infinite loop on the current thread in an utility method which look like below:
public static <T> Future<T> getFirstDone(List<Future<T>> futures) {
while (true) {
for (Future<T> future : futures) {
if (future.isDone()) {
return future;
}
}
// Break if necessary infinite loop here once it reaches certain timeout.
}
}
Usage:
List<Future<Foo>> results = collectThemSomehow();
Future<Foo> firstDoneResult = getFirstDone(results);
// ...
Here is an example of how it can works with Spring. In this example, the asynchronous job simply returns a boolean.
public void example(Job job) throws Exception
{
Future<Boolean> executor = jobExecutor.doJob(job);
//wait to be done
while (!executor.isDone()) {
Thread.sleep(10);
}
System.out.println(executor.get());
}
The job executor class is annoted #Component.
#Async
public Future<Boolean> doJob(Job job) throws Exception {
boolean isSuccessful;
//do something
return new AsyncResult<Boolean>(isSuccessful);
}
Sometimes you can invert it - transfer function pointer to async method and call it:
AtomicBoolean executed = new AtomicBoolean(false);
Runnable r = () ->{
if(!executed.getAndSet(true)){
//do job
}
};
But be careful: this code is executed inside worker thread, not original thread.

Using one Java 8 Consumer as Runnable Callback - is threadsafe?

I have a ScheduledThreadPoolExecutor with 4 active Threads. It gets filled with a bunch of tasks, where each task processes a chunk of items.
Each task must have 3 callbacks: Start, End, and one after each processed item.
Every callback triggers an update in my database. Which is a kinda long running task.
Here's a piece of sample code, that should illustrate what I'm doing:
public static void main(String[] args) throws InterruptedException {
ScheduledThreadPoolExecutor executor = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(4);
Consumer<String> processed = (String o) -> {
System.err.println("PROCESSED: " + o);
try { Thread.sleep(10); }
catch (Exception e) { e.printStackTrace(); }
};
for(int i=0; i<10; i++) {
executor.schedule(
new ChunkTask("task"+i, processed),
500,
TimeUnit.MILLISECONDS
);
}
}
public static class ChunkTask implements Runnable {
String taskId;
Consumer<String> processedCallback;
public ChunkTask(String taskId, Consumer<String> processedCallback) {
this.taskId = taskId;
this.processedCallback = processedCallback;
}
#Override
public void run() {
for(int i=0; i<50; i++) {
processedCallback.accept(taskId+" "+i);
}
}
}
I just omitted the start and end callbacks, because it's basically the same as the processed callback.
As you can see, I create a single Consumer object. Which has a Thread.sleep(10) to simulate database access. This object is getting called by all 4 Threads in parallel.
I wonder if this is thread safe. In my opinion, the Consumer is just a stateless object, with a stateless method. Though it can be called as many times you like in parallel.
Am I right?
EDIT: I know that my callback is synchronous. This is just for testing. Later I'd like to make it async.
Yes, your consumer doesn't have any state, so it's thread-safe. The only shared object it uses is System.err, which is itself thread-safe.
Of course, in the real code, the thread-safety will depend on what you do instead of printing to System.err. If you use a shared database service and this service is not thread-safe, then you'll have problems.

FutureTask Submitted to an Executor Doesn't Run

I've written a class, a series of instances of which are intended to be called from an AsyncTask, which will return a result from the method runReport(). It creates a worker thread just fine, but for some reason it then doesn't execute the Callable's call() method. What am I doing wrong?
//Problem: doStuff() never gets called, even though the worker thread gets created.
#Override
public ReportResult runReport() throws InterruptedException, ExecutionException {
Callable<ReportResult> report = new Callable<ReportResult>() {
#Override
public ReportResult call() throws Exception {
doStuff();
...
return new ReportResult(varWrittenByMethod);
}
};
FutureTask<ReportResult> result = new FutureTask<ReportResult>(report);
//I tried a few of these ExecutorService factory methods, with the same result.
//I only made my own ThreadFactory to verify the worker was created
ExecutorService es = Executors.newSingleThreadExecutor(new ThreadFact());
es.submit(report);
ReportResult finalResult = result.get();
es.shutdownNow();
return finalResult;
}
private class ThreadFact implements ThreadFactory{
#Override
public Thread newThread(Runnable r) {
Log.d(TAG, "Created worker Thread");
return new Thread(r);
}
}
As far as I can tell, I have to do this as a FutureTask in its own Thread, because it needs to do the following (all of which apart from the return is inside doStuff() ):
Do heavy some synchronous setup (The AsyncTask keeps that off the UI thread)
Call Looper.prepare()
Register a listener
Call Looper.loop(), catch a few callbacks from the listener over a period of time.
Call Looper.myLooper().quit() inside the listener callback when I have enough datapoints
Return the result
I'm open to better ways to do this. I originally let the AsyncTask make this call, then ran Looper.loop() on its thread, but I couldn't process a queue of these objects since I needed to call Looper.myLooper.quit() from the listener before returning a result, which poisoned the thread's message queue irreversibly.
Your thread factory doesn't propagate the passed Runnable to the created thread. In your ThreadFactory, try:
return new Thread(r);
Also, you should be using the FutureTask returned by the submit method, not the one you created explicitly. E.g.
FutureTask<ReportResult> result = es.submit(report);
ReportResult finalResult = result.get();
As a note, you probably will regret doing this level of work from an AsyncTask, because the threads in an AsyncTask will get killed during an Activity lifecycle change. Better to do the asynchronous setup in an IntentService. If you don't need Looper(), you can use plain threads rather than HandlerThreads.

Is there a way to add a listener to an Executor/Future's?

Java : Is there a way to add a listener to an Executor?
I have a collection with Futures which I try to monitorize , as to update some GUI statuses. Currently I am checking in a background thread if there are differences in the submitted/completed tasks, but I am doing this in a while(true){} block and I do not like this approach.
You could use SwingWorkers or similar classes depending on your GUI toolkit to get notified when a task completes.
Unfortunately, there is no way to do that.
Instead, use Google's ListenableFuture<V> interface.
Alternatively, use a language with better async support, such as C# and the TPL.
If you want to do something when the task completes, you add it to the task itself.
public static <T> void addTask(Callable<T> tCall) {
executor.submit(new Runnable() {
public void run() {
T t = tCall.call();
// what you want done when the task completes.
process(t);
}
});
}
Use java.util.concurrent.ExecutorCompletionService instead of Executor to submit tasks. It has method take() which returns recently completed task. Start additional thread (or SwingWorker) which would call take() in a loop, and update GUI status with the result.
I did something similar to #Peter Lawrey's answer.
I added a listener as a member variable of the callable and called that listener just before the Callable returned its result.
So you have a Listener interface:
#FunctionalInterface
public interface Listener<T> {
void notify(T result);
}
A Callable with that as a member variable:
public class CallbackCallable implements Callable<String>{
private Listener<String> listener;
#Override
public String call() throws Exception {
// do some stuff
if (listener != null)
listener.notify("result string");
return "result string";
}
public void setListener(Listener<String> listener) {
this.listener = listener;
}
}
And in your application you pass an implementation of the listener with what you want to be done with the result:
public static void main(String[] args) {
ExecutorService es = Executors.newSingleThreadExecutor();
System.out.println("This is thread: " + Thread.currentThread().getName());
CallbackCallable myCallable = new CallbackCallable();
myCallable.setListener(r -> {
// process your callable result here
System.out.println("Got from Callable: " + r);
System.out.println("This is thread: " + Thread.currentThread().getName());
});
es.submit(myCallable);
}
Only thing you need to keep in mind is that your implementation will run on the same thread as the Callable, as you can see if you run that:
This is thread: main
Got from Callable: result string
This is thread: pool-1-thread-1

Logic Problem between Main Class and Thread Class

Hy!!
I make a new Object from a Thread Class. There is a Http-Post in the run method with a result string.
My Question:
How is it possible to notify the main class that the download finished?
MFG
Have a look at the AsyncTask class which helps you handling work on another thread than the UI thread. It's a very useful class of the Android framework.
You simply create a custom class which inherits from AsyncTask and then you override the doInBackground() and insert the code that should be executed in its own thread. In your case this would be the code to do the download. Furthermore you have to override the onPostExecute() which is called automatically when the doInBackground() method has finished. The object you returned in the doInBackground() method will be automatically passed to the onPostExecute() method. The onPostExecute() will be execute on the UI thread.
So the AsyncTask class will handle all the thread stuff for you and you can focus on your work.
Have a look at the tutorial on the Android Developer site.
If by "main class" you mean your Activity then you can use a Handler.
In your activity:
private static final int DOWNLOAD_COMPLETE = 0;
...
private Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
switch(msg.what){
case DOWNLOAD_COMPLETE:
Log.d("MYTAG",msg.obj.toString());
break;
}
}
}
And in some other class:
public doBackgroundUpdate(Handler handler){
Thread backgroundThread = new Thread() {
#Override
public void run() {
// do long-running post operation
// send result back to UI thread
Message msg = Message.obtain();
msg.what = DOWNLOAD_COMPLETE;
msg.obj = "Result String to pass";
handler.sendMessage(msg);
}
}
backgroundThread.start();
}
Instead of creating a thread, create a Callable and pass it to an ExecutorService by way of the submit() method:
Future<T> submit(Callable<T> task)
Submitting a Callable object to the ExecutorService returns a Future object. The get() method of Future will then block until the task has completed and will contain the results of the Callable.
Example:
Callable<String> callable = new Callable<String>(){
#Override
public String call() throws Exception {
return "HELLO WORLD";
}
};
//executor with one thread
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> future = executor.submit(callable);
executor.shutdown();
String result = future.get();
System.out.println(result);

Categories