用于Object.wait的elapsedRealtime模拟

时间:2013-10-21 12:46:33

标签: java android multithreading wait notify

我在我的Android应用服务中使用了Object.wait(timeout)。但它不计算在“深度睡眠模式”下花费的时间。我使用AlarmManager定期唤醒我的应用程序,因此从深度睡眠中醒来不是问题。问题是wait(60000)在100秒深度睡眠后不会终止。

当我在SystemClock帮助页面上阅读时,object.wait使用了uptimeMillis()方法,该方法会在深度睡眠中停止计数。根据我的需要,最好使用elapsedRealtime()

如何使用Object.wait(timeout)方法实现{{1}}的模拟?或者我可以使用什么?


我使用此方法的任务之一是生成“ping”数据包,以便在没有其他数据包在队列中一段时间​​时通过网络发送。

3 个答案:

答案 0 :(得分:1)

你提到(在评论中){​​{1}}导致终止(杀死)线程,虽然这是完全错误的,但它只是向等待/加入/休眠线程抛出异常。

interrupt()
问题出在这里,因为你将所有业务放在public void Foo implements Runnable{ public void run(){ //do some work try{Thread.sleep(10000);}catch(Exception ex){/*when thread got interrupted*/} //do something else } } 块中,所以中断导致代码跳转到try块之后没有任何业务,所以这不是线程事。

答案 1 :(得分:1)

我建议您使用以下任何一种方法,而不是使用普通的Object.wait()或Thread.sleep();

  1. 使用java.util.concurrent.newScheduledThreadPool,它可以安排具有固定间隔或延迟的任务。使用threadCount = 1初始化线程池会为您提供一个线程。

  2. 使用java.util.Timer,它允许您安排TimerTask。

  3. 我认为1.是首选方法。

    如果您有特定要求要插入计时器对象或使用特定或第三方计时提供程序,您需要做的是编写自己的调度程序,它包装ScheduledExecutorService,然后使用您的转换时间自己的计时器或从你自己的计时器获得时间。基本上,您可以使用自己的时间计算在已打包的服务上启动计划任务。

    我在演员模型中有一个这样的调度程序样本,如下所示。看一下这个包中的DefaultScheduler。它可能有点儿马车(我还没有完全测试过它),但它应该给你一个好主意。

    http://sourceforge.net/p/jalgo/code-0/HEAD/tree/trunk/src/org/as/algo/threading/

答案 2 :(得分:0)

不确定它是否完全符合您的要求,但我写了这个暂停一段时间,但让其他线程过早地叫醒我。

它在内部使用BlockingQueue进行休眠,因此避免使用sleepwait以及随之而来的所有悲伤。

不确定它在Android下的行为方式,我不会使用它,但我怀疑您现有的AlarmManager工作会适应。

/**
 * Use one of these to doze for a certain time.
 *
 * The dozing is fully interruptable.
 *
 * Another thread can stop the caller's doze with either a wakeup call or an abort call.
 *
 * These can be interpreted in any way you like but it is intended that a Wakeup is
 * interpreted as a normal awakening and should probably be treated in exactly the
 * same way as an Alarm. An Abort should probably be interpreted as a suggestion
 * to abandon the process.
 */
public class Doze {
  // Special alarm messages.
  public enum Alarm {
    // Standard timeout.
    Alarm,
    // Forced wake from your doze.
    Wakeup,
    // Abort the whole Doze process.
    Abort;
  }
  // My queue to wait on.
  private final BlockingQueue<Alarm> doze = new ArrayBlockingQueue<>(1);
  // How long to wait by default.
  private final long wait;

  public Doze(long wait) {
    this.wait = wait;
  }

  public Doze() {
    this(0);
  }

  public Alarm doze() throws InterruptedException {
    // Wait that long.
    return doze(wait);
  }

  public Alarm doze(long wait) throws InterruptedException {
    // Wait that long.
    Alarm poll = doze.poll(wait, TimeUnit.MILLISECONDS);
    // If we got nothing then it must be a normal wakeup.
    return poll == null ? Alarm.Alarm : poll;
  }

  public void wakeup() {
    // Just post a Wakeup.
    doze.add(Alarm.Wakeup);
  }

  public void abort() {
    // Signal the system to abort.
    doze.add(Alarm.Abort);
  }

  private static long elapsed ( long start ) {
    return System.currentTimeMillis() - start;
  }

  // Test code.
  public static void main(String[] args) throws InterruptedException {
    // Doze for 1 second at a time.
    final Doze d = new Doze(1 * 1000);
    final long start = System.currentTimeMillis();

    // Start a dozing thread.
    new Thread(new Runnable() {
      @Override
      public void run() {
        try {
          Alarm a = d.doze();
          // Wait forever until we are aborted.
          while (a != Alarm.Abort) {
            System.out.println(elapsed(start) + ": Doze returned " + a);
            a = d.doze();
          }
          System.out.println(elapsed(start) + ": Doze returned " + a);
        } catch (InterruptedException ex) {
          // Just exit on interrupt.
        }
      }

    }).start();


    // Wait for a few seconds.
    Thread.sleep(3210);

    // Wake it up.
    d.wakeup();

    // Wait for a few seconds.
    Thread.sleep(4321);

    // Abort it.
    d.abort();


  }

}