object SynchronizedFuture extends WartTraverser
When a synchronized
block returns a scala.concurrent.Future, then the synchronization
typically does not extend to the computations performed inside the future. This often hides a
concurrency bug that is hard to spot during review because the computation's code is lexically
inside the synchronized block and it may not be obvious that scala.concurrent.Futures are in
play.
For example, synchronized
blocks are often used to read and update the state of an object
atomically. When the update operation involves a scala.concurrent.Future like below, then
the write to the state is actually not guarded by the synchronized call and the update is not
atomic.
synchronized { val x = this.atomicRef.get() futureComputation(x).map { y => this.atomicRef.set(y) y } }
The proper approach in the above example is to use a semaphore instead of a synchronized
block.
blocking { this.semaphore.acquire() } val x = this.atomicRef.get() futureComputation(x).map { y => this.atomicRef.set(y) y }.thereafter { _ => this.semaphore.release() }
If the synchronization intentionally does not have to extend over the scala.concurrent.Future computation, it usually helps with readability to move the future out of the synchronized block. For example,
blocking(synchronized {
val x = criticalSection()
Future { nonCriticalSection(x) }
})
should be written as follows:
val x = blocking(synchronized { criticalSection() })
Future { nonCriticalSection(x) }
There are cases where the synchronized
block is supposed to return a
scala.concurrent.Future, for example when dealing with the promise of a future. In such a
case, the warning should simply be suppressed locally.
- Alphabetic
- By Inheritance
- SynchronizedFuture
- WartTraverser
- AnyRef
- Any
- Hide All
- Show All
- Public
- Protected
Value Members
- final def !=(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
- final def ##: Int
- Definition Classes
- AnyRef → Any
- final def ==(arg0: Any): Boolean
- Definition Classes
- AnyRef → Any
- def apply(u: WartUniverse): Traverser
- Definition Classes
- SynchronizedFuture → WartTraverser
- def asAnnotationMacro(c: Context)(annottees: scala.reflect.macros.blackbox.Context.Expr[Any]*): scala.reflect.macros.blackbox.Context.Expr[Any]
- Definition Classes
- WartTraverser
- final def asInstanceOf[T0]: T0
- Definition Classes
- Any
- def asMacro(c: Context)(expr: scala.reflect.macros.blackbox.Context.Expr[Any]): scala.reflect.macros.blackbox.Context.Expr[Any]
- Definition Classes
- WartTraverser
- lazy val className: String
- Definition Classes
- WartTraverser
- def clone(): AnyRef
- Attributes
- protected[lang]
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.CloneNotSupportedException]) @IntrinsicCandidate() @native()
- def compose(o: WartTraverser): WartTraverser
- Definition Classes
- WartTraverser
- final def eq(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef
- def equals(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef → Any
- def error(u: WartUniverse)(pos: scala.reflect.api.Universe.Position, message: String): Unit
- Definition Classes
- WartTraverser
- final def getClass(): Class[_ <: AnyRef]
- Definition Classes
- AnyRef → Any
- Annotations
- @IntrinsicCandidate() @native()
- def hasTypeAscription(u: WartUniverse)(tree: scala.reflect.api.Universe.ValOrDefDef): Boolean
- Definition Classes
- WartTraverser
- def hasWartAnnotation(u: WartUniverse)(tree: scala.reflect.api.Universe.Tree): Boolean
- Definition Classes
- WartTraverser
- def hashCode(): Int
- Definition Classes
- AnyRef → Any
- Annotations
- @IntrinsicCandidate() @native()
- def isAnonymousFunctionName(u: WartUniverse)(t: scala.reflect.api.Universe.TypeName): Boolean
- Definition Classes
- WartTraverser
- final def isInstanceOf[T0]: Boolean
- Definition Classes
- Any
- def isPrimitive(u: WartUniverse)(t: scala.reflect.api.Universe.Type): Boolean
- Definition Classes
- WartTraverser
- def isPrivate(u: WartUniverse)(t: scala.reflect.api.Universe.ValOrDefDef): Boolean
- Definition Classes
- WartTraverser
- def isPublic(u: WartUniverse)(t: scala.reflect.api.Universe.ValOrDefDef): Boolean
- Definition Classes
- WartTraverser
- def isSynthetic(u: WartUniverse)(t: scala.reflect.api.Universe.Tree): Boolean
- Definition Classes
- WartTraverser
- def isSyntheticPartialFunction(u: WartUniverse)(tree: scala.reflect.api.Universe.Tree): Boolean
- Definition Classes
- WartTraverser
- def isWartAnnotation(u: WartUniverse)(a: scala.reflect.api.Universe.Annotation): Boolean
- Definition Classes
- WartTraverser
- val messageSynchronized: String
- final def ne(arg0: AnyRef): Boolean
- Definition Classes
- AnyRef
- final def notify(): Unit
- Definition Classes
- AnyRef
- Annotations
- @IntrinsicCandidate() @native()
- final def notifyAll(): Unit
- Definition Classes
- AnyRef
- Annotations
- @IntrinsicCandidate() @native()
- final def synchronized[T0](arg0: => T0): T0
- Definition Classes
- AnyRef
- def toString(): String
- Definition Classes
- AnyRef → Any
- final def wait(arg0: Long, arg1: Int): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.InterruptedException])
- final def wait(arg0: Long): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.InterruptedException]) @native()
- final def wait(): Unit
- Definition Classes
- AnyRef
- Annotations
- @throws(classOf[java.lang.InterruptedException])
- def warning(u: WartUniverse)(pos: scala.reflect.api.Universe.Position, message: String): Unit
- Definition Classes
- WartTraverser
- lazy val wartName: String
- Definition Classes
- WartTraverser
- def wasInferred(u: WartUniverse)(t: scala.reflect.api.Universe.TypeTree): Boolean
- Definition Classes
- WartTraverser