Synchronize the change handlers
I'm pretty confident that this isn't actually required by the JavaFX threading model, but it makes the code more obviously correct and uncontended synchronization has a negligible cost when we're talking about UI-level changes.
This commit is contained in:
parent
3f30eb32c2
commit
13e841d613
@ -8,6 +8,13 @@ import scalafx.beans.property._
|
|||||||
import scalafx.beans.value._
|
import scalafx.beans.value._
|
||||||
|
|
||||||
trait ObservableImplicits {
|
trait ObservableImplicits {
|
||||||
|
/* NOTE: (Sarah) I believe that the synchronization in these helpers is not
|
||||||
|
* _really_ required in the JavaFX threading model. However, the overhead of
|
||||||
|
* uncontended synchronization is relatively low, and typical UIs won't have
|
||||||
|
* enough change events for it to be a serious issue. (If you're updating
|
||||||
|
* a property in a tight loop, I expect you'll have bigger performance
|
||||||
|
* issues.)
|
||||||
|
*/
|
||||||
implicit val observableInstances = new Applicative[Observable] with Functor[Observable] with Monad[Observable] {
|
implicit val observableInstances = new Applicative[Observable] with Functor[Observable] with Monad[Observable] {
|
||||||
/* Map can be derived from `ap`, but this adds less overhead. */
|
/* Map can be derived from `ap`, but this adds less overhead. */
|
||||||
override def map[A, B](a: Observable[A])(f: A => B): ObservableValue[B, B] = {
|
override def map[A, B](a: Observable[A])(f: A => B): ObservableValue[B, B] = {
|
||||||
@ -18,7 +25,7 @@ trait ObservableImplicits {
|
|||||||
val prop = ObjectProperty[B](originalValue)
|
val prop = ObjectProperty[B](originalValue)
|
||||||
|
|
||||||
var prevValue = originalValue
|
var prevValue = originalValue
|
||||||
def changeHandler = {
|
def changeHandler = prop.synchronized {
|
||||||
val newVal = recalculate()
|
val newVal = recalculate()
|
||||||
if (prevValue != newVal) {
|
if (prevValue != newVal) {
|
||||||
prop.value = recalculate()
|
prop.value = recalculate()
|
||||||
@ -44,7 +51,7 @@ trait ObservableImplicits {
|
|||||||
|
|
||||||
var prevValue = originalValue
|
var prevValue = originalValue
|
||||||
|
|
||||||
def changeHandler = {
|
def changeHandler = prop.synchronized {
|
||||||
val newVal = recalculate()
|
val newVal = recalculate()
|
||||||
if (prevValue != newVal) {
|
if (prevValue != newVal) {
|
||||||
prop.value = newVal
|
prop.value = newVal
|
||||||
@ -74,7 +81,7 @@ trait ObservableImplicits {
|
|||||||
|
|
||||||
var prevValue = originalValue
|
var prevValue = originalValue
|
||||||
|
|
||||||
def innerHandle() = {
|
def innerHandle() = prop.synchronized {
|
||||||
val newVal = calc()
|
val newVal = calc()
|
||||||
if (prevValue != newVal) {
|
if (prevValue != newVal) {
|
||||||
prop.value = newVal
|
prop.value = newVal
|
||||||
@ -84,7 +91,7 @@ trait ObservableImplicits {
|
|||||||
var innerSub = oa() onChange innerHandle
|
var innerSub = oa() onChange innerHandle
|
||||||
|
|
||||||
var prevOuter = oa()
|
var prevOuter = oa()
|
||||||
def outerHandle() = {
|
def outerHandle() = prop.synchronized {
|
||||||
val newOuter = oa()
|
val newOuter = oa()
|
||||||
/* We need reference equality here: we're subscribing to a specific object. */
|
/* We need reference equality here: we're subscribing to a specific object. */
|
||||||
if (prevOuter ne newOuter) {
|
if (prevOuter ne newOuter) {
|
||||||
|
Loading…
Reference in New Issue
Block a user