@@ -6,13 +6,13 @@ package akka.actor
66
77import java .util .concurrent .atomic .AtomicReference
88
9+ import scala .annotation .nowarn
910import scala .annotation .tailrec
1011import scala .concurrent .ExecutionContext
1112import scala .concurrent .duration ._
1213import scala .util .control .NoStackTrace
1314
14- import scala .annotation .nowarn
15-
15+ import akka .actor .Scheduler .AtomicCancellable
1616import akka .annotation .InternalApi
1717import akka .util .JavaDurationConverters
1818
@@ -72,49 +72,23 @@ trait Scheduler {
7272 */
7373 def scheduleWithFixedDelay (initialDelay : FiniteDuration , delay : FiniteDuration )(runnable : Runnable )(
7474 implicit executor : ExecutionContext ): Cancellable = {
75- try new AtomicReference [Cancellable ](Cancellable .initialNotCancelled) with Cancellable { self =>
76- compareAndSet(
77- Cancellable .initialNotCancelled,
78- scheduleOnce(
79- initialDelay,
80- new Runnable {
81- override def run (): Unit = {
82- try {
83- runnable.run()
84- if (self.get != null )
85- swap(scheduleOnce(delay, this ))
86- } catch {
87- // ignore failure to enqueue or terminated target actor
88- case _ : SchedulerException =>
89- case e : IllegalStateException if e.getCause != null && e.getCause.isInstanceOf [SchedulerException ] =>
90- }
75+ new AtomicCancellable (Cancellable .initialNotCancelled, stateRef => {
76+ scheduleOnce(
77+ initialDelay,
78+ new Runnable {
79+ override def run (): Unit = {
80+ try {
81+ runnable.run()
82+ if (stateRef.get != null )
83+ stateRef.swap(scheduleOnce(delay, this ))
84+ } catch {
85+ // ignore failure to enqueue or terminated target actor
86+ case _ : SchedulerException =>
87+ case e : IllegalStateException if e.getCause != null && e.getCause.isInstanceOf [SchedulerException ] =>
9188 }
92- }))
93-
94- @ tailrec private def swap (c : Cancellable ): Unit = {
95- get match {
96- case null => if (c != null ) c.cancel()
97- case old => if (! compareAndSet(old, c)) swap(c)
98- }
99- }
100-
101- final def cancel (): Boolean = {
102- @ tailrec def tailrecCancel (): Boolean = {
103- get match {
104- case null => false
105- case c =>
106- if (c.cancel()) compareAndSet(c, null )
107- else compareAndSet(c, null ) || tailrecCancel()
10889 }
109- }
110-
111- tailrecCancel()
112- }
113-
114- override def isCancelled : Boolean = get == null
115- } catch {
116- case SchedulerException (msg) => throw new IllegalStateException (msg)
117- }
90+ })
91+ })
11892 }
11993
12094 /**
@@ -562,4 +536,40 @@ object Scheduler {
562536 * a custom implementation of `Scheduler` must also implement this.
563537 */
564538 trait TaskRunOnClose extends Runnable
539+
540+ private [akka] class AtomicCancellable (initialValue : Cancellable , next : AtomicCancellable => Cancellable )
541+ extends AtomicReference [Cancellable ](initialValue)
542+ with Cancellable { self =>
543+
544+ try {
545+ compareAndSet(initialValue, next(self))
546+ } catch {
547+ case cause @ SchedulerException (msg) => throw new IllegalStateException (msg, cause)
548+ }
549+
550+ @ tailrec final private [akka] def swap (c : Cancellable ): Unit = {
551+ get match {
552+ case null => if (c != null ) c.cancel()
553+ case old =>
554+ if (! compareAndSet(old, c))
555+ swap(c)
556+ }
557+ }
558+
559+ final def cancel (): Boolean = {
560+ @ tailrec def tailrecCancel (): Boolean = {
561+ get match {
562+ case null => false
563+ case c =>
564+ if (c.cancel()) compareAndSet(c, null )
565+ else compareAndSet(c, null ) || tailrecCancel()
566+ }
567+ }
568+
569+ tailrecCancel()
570+ }
571+
572+ final override def isCancelled : Boolean = get == null
573+
574+ }
565575}
0 commit comments