@@ -12,6 +12,7 @@ import scala.concurrent.ExecutionContext
1212import scala .concurrent .duration ._
1313import scala .util .control .NoStackTrace
1414
15+ import akka .actor .Scheduler .AtomicCancellable
1516import akka .annotation .InternalApi
1617import akka .util .JavaDurationConverters
1718
@@ -70,51 +71,25 @@ trait Scheduler {
7071 * Note: For scheduling within actors `with Timers` should be preferred.
7172 */
7273 def scheduleWithFixedDelay (initialDelay : FiniteDuration , delay : FiniteDuration )(runnable : Runnable )(
73- implicit executor : ExecutionContext ): Cancellable = {
74- try new AtomicReference [Cancellable ](Cancellable .initialNotCancelled) with Cancellable { self =>
75- compareAndSet(
76- Cancellable .initialNotCancelled,
74+ implicit executor : ExecutionContext ): Cancellable =
75+ new AtomicCancellable (Cancellable .initialNotCancelled) {
76+ final override protected def next (): Cancellable =
7777 scheduleOnce(
7878 initialDelay,
7979 new Runnable {
8080 override def run (): Unit = {
8181 try {
8282 runnable.run()
83- if (self. get != null )
83+ if (get != null )
8484 swap(scheduleOnce(delay, this ))
8585 } catch {
8686 // ignore failure to enqueue or terminated target actor
8787 case _ : SchedulerException =>
8888 case e : IllegalStateException if e.getCause != null && e.getCause.isInstanceOf [SchedulerException ] =>
8989 }
9090 }
91- }))
92-
93- @ tailrec private def swap (c : Cancellable ): Unit = {
94- get match {
95- case null => if (c != null ) c.cancel()
96- case old => if (! compareAndSet(old, c)) swap(c)
97- }
98- }
99-
100- final def cancel (): Boolean = {
101- @ tailrec def tailrecCancel (): Boolean = {
102- get match {
103- case null => false
104- case c =>
105- if (c.cancel()) compareAndSet(c, null )
106- else compareAndSet(c, null ) || tailrecCancel()
107- }
108- }
109-
110- tailrecCancel()
111- }
112-
113- override def isCancelled : Boolean = get == null
114- } catch {
115- case SchedulerException (msg) => throw new IllegalStateException (msg)
91+ })
11692 }
117- }
11893
11994 /**
12095 * Java API: Schedules a `Runnable` to be run repeatedly with an initial delay and
@@ -561,4 +536,42 @@ object Scheduler {
561536 * a custom implementation of `Scheduler` must also implement this.
562537 */
563538 trait TaskRunOnClose extends Runnable
539+
540+ private [akka] abstract class AtomicCancellable (initialValue : Cancellable )
541+ extends AtomicReference [Cancellable ](initialValue)
542+ with Cancellable { self =>
543+
544+ try {
545+ compareAndSet(initialValue, next())
546+ } catch {
547+ case cause @ SchedulerException (msg) => throw new IllegalStateException (msg, cause)
548+ }
549+
550+ protected def next (): Cancellable
551+
552+ @ tailrec final protected def swap (c : Cancellable ): Unit = {
553+ get match {
554+ case null => if (c != null ) c.cancel()
555+ case old =>
556+ if (! compareAndSet(old, c))
557+ swap(c)
558+ }
559+ }
560+
561+ final def cancel (): Boolean = {
562+ @ tailrec def tailrecCancel (): Boolean = {
563+ get match {
564+ case null => false
565+ case c =>
566+ if (c.cancel()) compareAndSet(c, null )
567+ else compareAndSet(c, null ) || tailrecCancel()
568+ }
569+ }
570+
571+ tailrecCancel()
572+ }
573+
574+ final override def isCancelled : Boolean = get == null
575+
576+ }
564577}
0 commit comments