@@ -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
@@ -71,48 +72,23 @@ trait Scheduler {
7172 */
7273 def scheduleWithFixedDelay (initialDelay : FiniteDuration , delay : FiniteDuration )(runnable : Runnable )(
7374 implicit executor : ExecutionContext ): Cancellable = {
74- try new AtomicReference [Cancellable ](Cancellable .initialNotCancelled) with Cancellable { self =>
75- compareAndSet(
76- Cancellable .initialNotCancelled,
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 }
11793 }
11894
@@ -561,4 +537,42 @@ object Scheduler {
561537 * a custom implementation of `Scheduler` must also implement this.
562538 */
563539 trait TaskRunOnClose extends Runnable
540+
541+ private [akka] abstract class AtomicCancellable (initialValue : Cancellable )
542+ extends AtomicReference [Cancellable ](initialValue)
543+ with Cancellable { self =>
544+
545+ try {
546+ compareAndSet(initialValue, next())
547+ } catch {
548+ case cause @ SchedulerException (msg) => throw new IllegalStateException (msg, cause)
549+ }
550+
551+ protected def next (): Cancellable
552+
553+ @ tailrec final protected def swap (c : Cancellable ): Unit = {
554+ get match {
555+ case null => if (c != null ) c.cancel()
556+ case old =>
557+ if (! compareAndSet(old, c))
558+ swap(c)
559+ }
560+ }
561+
562+ final def cancel (): Boolean = {
563+ @ tailrec def tailrecCancel (): Boolean = {
564+ get match {
565+ case null => false
566+ case c =>
567+ if (c.cancel()) compareAndSet(c, null )
568+ else compareAndSet(c, null ) || tailrecCancel()
569+ }
570+ }
571+
572+ tailrecCancel()
573+ }
574+
575+ final override def isCancelled : Boolean = get == null
576+
577+ }
564578}
0 commit comments