Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is Thread.sleep(x) accurate enough to use as a clock in Android?

I have a separate thread running in my main class. It needs to send a message every 100 milliseconds, but EXACTLY every 100ms. I am wondering if it is accurate enough to be used as such, or if there is an alternative to have something happen exactly 10 times a second.

class ClockRun implements Runnable {

    @Override
    public void run() {
        double hourlyRate = Double.parseDouble(prefs.getString("hourlyRate", ""));
        double elapsedTime = 0;
        do {
            while(clockRun){
                double amount = hourlyRate / 360 /100 * elapsedTime;
                elapsedTime++;
                Bundle clockData = new Bundle();
                clockData.putString("value", String.format("$%.2f", amount));

                Message message = Message.obtain();
                message.setData(clockData);


                handler.sendMessage(message);

                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }while (mainRun);

        Notify.viaToast(getApplication(), "Thread stopped.");

    }
}
like image 546
shlomo_maghen Avatar asked Oct 25 '15 22:10

shlomo_maghen


2 Answers

No it is not accurate at all,

From the docs:

(temporarily cease execution) for the specified number of milliseconds, subject to the precision and accuracy of system timers and schedulers. In other words, this sleep is OS or environment dependant, you can't predict the OS scheduling decision, plus, the sleep can be terminated by an interrupt.

Again from the docs:

In any case, you cannot assume that invoking sleep will suspend the thread for precisely the time period specified

Moreover, it is not efficient because you will be wasting CPU cycles just for sleeping.

ScheduledExecutorService will provide a better precision and performance. Simply wrap your task in Callable or Runnable and use ScheduledExecutorService to execute them, there are plenty of tutorials out there.

like image 121
Sleiman Jneidi Avatar answered Oct 06 '22 22:10

Sleiman Jneidi


I recommend using ScheduledThreadPoolExecutor's scheduleAtFixedRate() method, because it fires every given time, no matter how long it takes for the code in run() method to complete.

I think it would be something like this:

Runnable runnable = new Runnable() {
    @Override
    public void run() {
            // Do your stuff      
    }
});

ScheduledExecutorService ses = Executors.newScheduledThreadPool(1);
ses.scheduleAtFixedRate(runnable, 0, 100, TimeUnit.MILLISECONDS);
like image 29
Jędrzej Kołtunowicz Avatar answered Oct 06 '22 23:10

Jędrzej Kołtunowicz