Replacing busy loop and sleep in thread


Replacing busy loop and sleep in thread



I have a Thread that calls a certain service.
The service defines a callback function that can be called multiple times
as long as there is data onProcessing().



The onCompletion() is called once it is finished.


public CallThread implements Runnable{
public boolean isCompleted = false;
public void run(){
ResponseObserver response = new ResponseObserver(){
public void onException(){
//Errors could happen sometimes so the program should just issue another request
}
public void onCompletion(){
isCompleted = true;
//process the result
}
public void onProcessing(){
//This could be called multiple time
}
}

//Service is the object that calls the service
Service service = getService();

while(!isCompleted){
//Request object is populated
Request request = supplyRequest();

service.getDetails(request, response);

//How to remove this sleep
Thread.sleep(10 * 1000);
}
}
}



I have created a busy loop that checks for the isCompleted and having it sleep.
What I am doing now..is to use sleep command to be able for the function to be completed
until issuing a next request.



I am not sure if this is optimal as sometimes..it does not take 10 seconds before
onCompletion() is called.
I just wanted the service to return something before I could issue another request.



Is there a way to optimized my code?





Is there a need to call service.getDetails() multiple times for the same request? If not there's no need for sleep(), as there's nothing meaningful happening in the thread itself after getDtails() call that will be dependent on onCompletion(), it doesn't make sense to keep it blocked.
– 11thdimension
Jul 1 at 7:11


service.getDetails()


sleep()


getDtails()


onCompletion()





Yes..the callback function could return an onException..say for example the dependent server is down... so in that case I should re-issue a new request.
– Mark Estrada
Jul 1 at 7:21





In that case too, thread is not needed, you just have to call the service in onException method.
– 11thdimension
Jul 1 at 7:22


onException





Ohh sorry..forgot to mention that this thread is being spawn by the main thread..so it is needed that this should run into completion... the main thread cannot proceed until this thread is finished
– Mark Estrada
Jul 1 at 7:24




2 Answers
2



It's probably going to be some combination of CountDownLatch. Try following


CountDownLatch


public class CallThread implements Runnable {
private final CountDownLatch completionLatch = new CountDownLatch(1);

public void run(){
callService();

//Wait without timeout, bad idea
try {
completionLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

public void callService() {
//Service is the object that calls the service
Service service = getService();
//Request object is populated
ResponseObserver response = new MyResponseObserver(completionLatch);
Request request = supplyRequest();
service.getDetails(request, response);
}

class MyResponseObserver {
private CountDownLatch completionLatch;

MyResponseObserver(CountDownLatch latch) {
this.completionLatch = latch;
}

public void onException(){
/* Retry on exception */
callService();
}
public void onCompletion(){
completionLatch.countDown();
//process the result
}
public void onProcessing(){
//This could be called multiple time
}
};
}



Besides that you can probably also consider using Callable instead of Runnable since main is waiting for the processing, probably its better to do in main thread itself. Below is a what it would look like


Callable


Runnable


main


public CallThread implements Callable<MyResult> {
private MyResult myResult;
private final CountDownLatch completionLatch = new CountDownLatch(1);

public MyResult call(){
callService();

//Wait without timeout, bad idea
try {
completionLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}

return myResult;
}

public setMyResult(MyResult myResult) {
this.myResult = myResult;
}

public void callService() {
//Service is the object that calls the service
Service service = getService();
//Request object is populated
ResponseObserver response = new MyResponseObserver(completionLatch);
Request request = supplyRequest();
service.getDetails(request, response);
}

class MyResponseObserver {
private CountDownLatch completionLatch;

MyResponseObserver(CountDownLatch latch) {
this.completionLatch = latch;
}

public void onException(){
/* Retry on exception */
callService();
}
public void onCompletion(){
completionLatch.countDown();
//process the result
setMyResult(result);

}
public void onProcessing(){
//This could be called multiple time
}
};
}



in main()


...
FutureTask task = new FutureTask(new CallThead());
new Thread(task).start();

MyResult result = task.get();//blocks thead





Question, in the first await method of using Runnable...If I put a time out there completionLatch.await(5, Timeout.Seconds); And the timeout happened.. isn't my run method would be completed and my thread will end?
– Mark Estrada
Jul 1 at 8:00





I'm still modifying the answer so please bear with me, regarding the question. A timeout is supposed to be an irrecoverable event for the latch. It's to avoid having an infinitely running blocked thread. For example you could probably set it to time out after 12 hours or something.
– 11thdimension
Jul 1 at 8:02





Thank you mate.. Learned a lot from this post.
– Mark Estrada
Jul 1 at 11:24



A CountDownLatch or CompletableFuture can be used to wait for a condition asynchronously:


CountDownLatch


CompletableFuture


public CallThread implements Runnable {
public boolean isCompleted = false;

@Override
public void run() {
// Try up to 5 calls

for (int i = 0; i < 5; ++i) {
// Create the observer
MyResponseObserver observer = new MyResponseObserver();

// Call the service
service.getDetails(supplyRequest(), observer);

try {
// Wait for the result
Boolean result = observer.completable.get();

// Or wait with a timeout
// observer.completable.get(30, TimeUnit.SECONDS);

// Completed successfully
isCompleted = true;
return;
} catch (ExecutionException e) {
// Completed with exception. Retry.
} catch (InterruptedException e) {
return;
}
}
}

/** Response callback handler */
private static class MyResponseObserver implements ResponseObserver {
/** Result object (change Boolean to the type of your result) */
public final CompletableFuture<Boolean> completable = new CompletableFuture<>();

@Override
public void onException() {
// Signal an error
completable.completeExceptionally(new Exception("Error"));
}

@Override
public void onCompletion() {
// Signal a result
completable.complete(true);
}

@Override
public void onProcessing() {
}
}
}





I have thought of using this latch..but the problem is that onException could happen several times. If that is the case then, it will not retry the call again.
– Mark Estrada
Jul 1 at 7:22





Also, a latch cant be reset right? Or it is possible but is it a good way on how it was designed to be used?
– Mark Estrada
Jul 1 at 7:42





Sorry I don't get what you mean..can you show me some code? Where can I do a retry, is it inside my busy loop....also, do I not need to do a reset of the latch? I am not that verse in java multithreading.
– Mark Estrada
Jul 1 at 7:48






Say for example, in my while loop..I waited for 30 sec and an error occurs..the onException is called.. then how can I retry my transaction?
– Mark Estrada
Jul 1 at 7:54





Thank you mate.. Learned a lot from this post.
– Mark Estrada
Jul 1 at 11:24






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

List of Kim Possible characters

Audio Livestreaming with Python & Flask

NSwag: Generate C# Client from multiple Versions of an API