简体   繁体   中英

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?

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

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() {
        }
    }
}

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

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM