Пример #1
0
  /**
   * Performs a selective receive. This method blocks (but for no longer than the given timeout)
   * until a message that is {@link MessageProcessor#process(java.lang.Object) selected} by the
   * given {@link MessageProcessor} is available in the mailbox, and returns the value returned by
   * {@link MessageProcessor#process(java.lang.Object) MessageProcessor.process}. If the given
   * timeout expires, this method returns {@code null}.
   *
   * <p>Messages that are not selected, are temporarily skipped. They will remain in the mailbox
   * until another call to receive (selective or non-selective) retrieves them.
   *
   * @param <T> The type of the returned value
   * @param timeout the duration to wait for a matching message to arrive.
   * @param unit timeout's time unit.
   * @param proc performs the selection.
   * @return The non-null value returned by {@link MessageProcessor#process(java.lang.Object)
   *     MessageProcessor.process}, or {@code null} if the timeout expired.
   * @throws InterruptedException
   */
  public final <T> T receive(long timeout, TimeUnit unit, MessageProcessor<? super Message, T> proc)
      throws TimeoutException, SuspendExecution, InterruptedException {
    assert Actor.currentActor() == null || Actor.currentActor() == actor;

    final Mailbox<Object> mailbox = actor.mailbox();

    actor.checkThrownIn0();
    mailbox.maybeSetCurrentStrandAsOwner();

    final long start = timeout > 0 ? System.nanoTime() : 0;
    long now;
    long left = unit != null ? unit.toNanos(timeout) : 0;
    final long deadline = start + left;

    actor.monitorResetSkippedMessages();
    QueueIterator<Object> it = mailbox.queue().iterator();
    for (int i = 0; ; i++) {
      if (actor.flightRecorder != null)
        actor.record(
            1,
            "SelctiveReceiveHelper",
            "receive",
            "%s waiting for a message. %s",
            this,
            timeout > 0
                ? "millis left: " + TimeUnit.MILLISECONDS.convert(left, TimeUnit.NANOSECONDS)
                : "");

      mailbox.lock();

      if (it.hasNext()) {
        final Object m = it.next();
        mailbox.unlock();
        if (m == currentMessage) {
          it.remove();
          continue;
        }

        actor.record(1, "SelctiveReceiveHelper", "receive", "Received %s <- %s", this, m);
        actor.monitorAddMessage();
        if (m instanceof LifecycleMessage) {
          it.remove();
          handleLifecycleMessage((LifecycleMessage) m);
        } else {
          final Message msg = (Message) m;
          currentMessage = msg;
          try {
            T res = proc.process(msg);
            if (res != null) {
              if (it.value()
                  == msg) // another call to receive from within the processor may have deleted msg
              it.remove();
              return res;
            }
          } catch (Exception e) {
            if (it.value()
                == msg) // another call to receive from within the processor may have deleted msg
            it.remove();
            throw e;
          } finally {
            currentMessage = null;
          }
          actor.record(1, "SelctiveReceiveHelper", "receive", "%s skipped %s", this, m);
          actor.monitorSkippedMessage();
        }
      } else {
        try {
          if (unit == null) mailbox.await(i);
          else if (timeout > 0) {
            mailbox.await(i, left, TimeUnit.NANOSECONDS);

            now = System.nanoTime();
            left = deadline - now;
            if (left <= 0) {
              actor.record(1, "Actor", "receive", "%s timed out.", this);
              throw new TimeoutException();
            }
          } else {
            return null;
          }
        } finally {
          mailbox.unlock();
        }
      }
    }
  }