【问题标题】:Android Thread.sleep sometimes waits far too longAndroid Thread.sleep 有时会等待太久
【发布时间】:2013-07-10 02:09:00
【问题描述】:

编辑:

这里不是说精度问题,从下面的代码和日志可以看出,我请求休眠1秒,结果却快200秒了,有时候能跳到600秒,这不可能精度问题..


我以前使用 handlerthread,有时发布到处理程序的作业没有按时开始,为了获得更多详细信息,我将其更改为基本线程,结果发现 Thread.sleep() 是问题,但我'不知道如何解决这个问题,可能的原因是什么?

hGpsThread = new Thread(mGpsWorker);
hGpsThread.start();

private final Runnable mGpsWorker = new Runnable() {
    @Override
    public void run() {
        long lastGpsRequestTime = 0;
        l.Write("GPS thread started.");
        while (isRunning) {
            l.Write("GPS thread loop start.");
            try {
                long currentTimeMillis = System.currentTimeMillis();
                if (currentTimeMillis >= lastGpsRequestTime + gpsUpdateInterval) {
                    l.Write("Requesting location update");
                    gpslib.getLocation();
                    lastGpsRequestTime = currentTimeMillis;
                }
                l.Write("GPS thread before sleep");
                Thread.sleep(1000);
                l.Write("GPS thread after sleep");
            } catch (InterruptedException e) {
            }
            l.Write("GPS thread loop end.");
        }
        l.Write("GPS thread ended.");
    }
};

注意:getLocation() 使用来自另一个线程的循环器调用 requestLocationUpdates,因此据我了解,位置更新不应影响该线程。

getLocation() 还会创建一个 Timer 并安排一个超时时间,这可能是问题所在吗?据我了解,这应该不是问题。

这是日志:(这只是偶尔发生,说机会接近 0.5%)

Wed Jul 10 11:45:46 AEST 2013 GPS thread loop start.
Wed Jul 10 11:45:46 AEST 2013 GPS thread before sleep
Wed Jul 10 11:49:04 AEST 2013 GPS thread after sleep
Wed Jul 10 11:49:04 AEST 2013 GPS thread loop end.

谢谢

测试环境为:HTC Aria,Android 2.2 看起来它只在使用电池运行时发生,但我的应用在充电状态下的行为并没有什么不同。

【问题讨论】:

  • 注释掉getLocation()会出现这种情况吗?看起来另一个线程并没有放弃 CPU,一旦这个线程进入sleep
  • @Aert,谢谢,我现在正在监控 CPU 使用率,如果我发现了什么,我会更新问题,谢谢。
  • 当Android显示器被电源按钮关闭或显示超时时,您是否这样做?
  • @RoystonPinto 是的,上面的代码来自前台服务类。实际上它看起来确实只在显示器关闭时发生!这也可以解释为什么在连接电源时没有发生这种情况,因为我将显示器设置为在连接电源时始终打开......所以有什么区别吗?
  • 是的,当显示器关闭时,处理程序和线程将暂停,直到被另一个应用程序中的某些唤醒锁唤醒或打开显示器时。因此,您观察到的随机行为是正确的。如果您在显示屏关闭时需要正确的行为,请切换到 AlarmManager,因为即使显示屏关闭也可以使用。

标签: android multithreading


【解决方案1】:

基本上Thread.sleep()Handlers 只要屏幕打开就可以正常工作(意味着Android 不应处于深度睡眠状态/屏幕关闭状态)。

当屏幕关闭时,默认的 Android 行为是暂停 Thread.sleep() 和 Handlers(),直到屏幕再次打开或被某个应用程序获取唤醒锁唤醒。因此,如果屏幕始终处于开启状态,您的应用程序将完美运行,但当它关闭时,它的行为就会不稳定。

最好的解决方法是切换到AlarmManager,因为当触发警报时,onRecieve() 总是默认获取唤醒锁,导致 Android 唤醒并执行。

【讨论】:

  • 谢谢。我有几个问题:这是否仅适用于由 UI 线程直接创建的线程,或者也适用于由设置为 Foreground 的 Service/IntentService 创建的线程?这也适用于等待(超时)吗?建议的 AlarmManager 是否一定会点亮屏幕? (我需要每 10 秒运行一次操作。)您能否提供问题文档的链接?再次,非常感谢。
【解决方案2】:

sleep() documentation 警告它不准确:

无法保证精度 - 线程可能会或多或少地休眠 比要求的多。

有许多与sleep() 缺乏精确度有关的问题,例如this onethis one 等等。谷歌“java线程睡眠精度”或“android线程睡眠精度”。

【讨论】:

  • 感谢回复,不过不是精度问题,我要求休眠1秒,结果差不多200秒,有时会跳到600秒,这不是精度问题。。 .
  • 我同意您的数字略有不同,但 API 的描述绝对没有任何承诺,尤其是 the Thread may sleep more or less than requested 的部分。如果您找到有关如何以精确数量入睡的更有用的信息,请将其作为答案发布并接受。这样做是公平的。
【解决方案3】:

我也讨厌这个问题,不是因为它不够精确,而是线程等待了 30 分钟而不是 10 秒 - 对于一个运行数周且必须定期执行请求的应用程序,这不是解决方案.因此,我制作了 BetterSleeper :-)

import java.sql.Timestamp;

public class BetterSleeper {

    public static void sleepSeconds(int seconds_to_wait) {
        System.out.println("START WAIT FOR "+seconds_to_wait+" SECONDS");
        BetterSleeper.sleepMillis(seconds_to_wait*1000);
        System.out.println("END WAIT");
    }

    public static void sleepMillis(int milliseconds_to_wait) {
        System.out.println("START WAIT FOR "+milliseconds_to_wait+" MILLISECONDS");
        Timestamp timestamp = new Timestamp(System.currentTimeMillis());
        long start_milliseconds = timestamp.getTime();
        long end_milliseconds = start_milliseconds + milliseconds_to_wait;
        while (true) {
            Timestamp endtime = new Timestamp(System.currentTimeMillis());
            if ((endtime.getTime()) >= end_milliseconds) {
                break;
            }
        }
        System.out.println("END WAIT");
    }
}

如果你考虑到这个 sn-p 中的处理时间实际上几乎没有影响,这实际上证明要准确得多,因为它会记住它什么时候开始,什么时候应该从一开始就停止。

另一个优点是你没有调度睡眠线程的所有缺点,如 Thread.sleep,如果你终止主线程,后台线程将被放弃。


注意我与 Android 开发无关 - 我的问题发生在运行 Windows 10 的 Windows PC 上。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-04
    • 1970-01-01
    • 1970-01-01
    • 2012-12-08
    • 1970-01-01
    • 2022-11-03
    相关资源
    最近更新 更多