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?
Asked
Active
Viewed 1.1k times
4
AmiguelS
- 805
- 2
- 10
- 28
2 Answers
6
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
ManagerwithExecutorServiceof your preferred choice. - Either your can pass
Callabackobject toCallable/Runnableobject Or you can createCallbackobject insideCallable/Runnable. In my example, I have explicitly passedCallbackobject toCallable. Before returning the result,
Callableobject invokesCallbackmethod. 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.
Ravindra babu
- 37,698
- 11
- 250
- 211
2
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
}
});
}
Peter Lawrey
- 525,659
- 79
- 751
- 1,130
-
The task is executed "off-device". This is a manager for BLE communication. Once the response is received through BLE, the callback is executed. Hence the though of a creating a thread for it. – AmiguelS Apr 06 '16 at 11:12
-
@AmiguelS you can still use a thread pool for these callbacks. If you have a communication library this usually has a thread for callbacks/notification of messages. – Peter Lawrey Apr 06 '16 at 11:16