Я дал себе библиотеку, чтобы сделать это.У меня есть
trait Poller extends AutoCloseable {
def addTask[T]( task : Poller.Task[T] ) : Future[T]
def close() : Unit
}
, где Poller.Task
выглядит как
class Task[T]( val label : String, val period : Duration, val pollFor : () => Option[T], val timeout : Duration = Duration.Inf )
. Poller
опрашивает каждый period
до тех пор, пока метод pollFor
не будет успешным (дает Some[T]
)или timeout
превышен.
Для удобства, когда я начинаю опрос, я оборачиваю это в Poller.Task.withDeadline
:
final case class withDeadline[T] ( task : Task[T], deadline : Long ) {
def timedOut = deadline >= 0 && System.currentTimeMillis > deadline
}
, который преобразует (неизменяемый, многоразовый) timeout
Продолжительность задачи до крайнего срока для попытки опроса для тайм-аута.
Для эффективного опроса я использую Java ScheduledExecutorService
:
def addTask[T]( task : Poller.Task[T] ) : Future[T] = {
val promise = Promise[T]()
scheduleTask( Poller.Task.withDeadline( task ), promise )
promise.future
}
private def scheduleTask[T]( twd : Poller.Task.withDeadline[T], promise : Promise[T] ) : Unit = {
if ( isClosed ) {
promise.failure( new Poller.ClosedException( this ) )
} else {
val task = twd.task
val deadline = twd.deadline
val runnable = new Runnable {
def run() : Unit = {
try {
if ( ! twd.timedOut ) {
task.pollFor() match {
case Some( value ) => promise.success( value )
case None => Abstract.this.scheduleTask( twd, promise )
}
} else {
promise.failure( new Poller.TimeoutException( task.label, deadline ) )
}
}
catch {
case NonFatal( unexpected ) => promise.failure( unexpected )
}
}
}
val millis = task.period.toMillis
ses.schedule( runnable, millis, TimeUnit.MILLISECONDS )
}
}
Кажется, это работаетну, не требуя сна или блокировки отдельных Threads
.
(Глядя на библиотеку, можно сделать многое, чтобы сделать ее более понятной, удобной для чтения и прояснить роль Poller.Task.withDeadline
сделав необработанный конструктор для этого класса private
. Крайний срок должен всегда вычисляться из задачи timeout
, не должен быть произвольной свободной переменной.)
Этот код взят из здесь (framework)и черта) и здесь (реализация) .(Если вы хотите использовать прямые координаты maven, то здесь .)