22.4. Synchronizacja

Język Scala umożliwia stosowanie znanych z języka Java mechanizmów związanych z programowaniem współbieżnym, takich jak wątki i synchronizacja dostępu do współdzielonych danych. Program z pliku Synch.scala jest przykładem wykorzystania tych mechanizmów.

Plik Synch.scala:
object Synch {
  def main(args: Array[String]) {
    val lock = new AnyRef
    var value = 0
    class Increment(remainder: Int) extends Runnable {
      override def run() {
        var j = 0
        while (j < 4) {
          lock.synchronized { 
            if (value % 2 == remainder) { 
              value += 1 
              println("Increment(" + remainder +
                      "): new value = " + value)
              j += 1
              lock.notify() 
            }
            else lock.wait() 
          }
        }
      }
    }
    val inc0 = new Thread(new Increment(0)) 
    val inc1 = new Thread(new Increment(1)) 
    inc0.start() 
    inc1.start() 
  }
}

Program tworzy (wiersze i ) i uruchamia (wiersze i ) dwa wątki, które na przemian zwiększają wartość współdzielonej zmiennej value o 1 (wiersz ). Jeden z wątków zmienia tą wartość tylko wtedy, gdy aktualna wartość jest parzysta, a drugi tylko wtedy, gdy ta wartość jest nieparzysta (wiersz ). Synchronizacja dostępu do zmiennej value jest uzyskiwana przy użyciu metody synchronized, wywołanej na obiekcie lock (wiersz ). Metoda synchronized pochodzi z klasy AnyRef i umożliwia synchronizację wykonania przekazanego jej argumentu. Obiekt, na którym metoda synchronized jest wykonywana, służy jako blokada. Wątek, który uzyskał blokadę i tym samym dostęp do synchronizowanego fragmentu kodu, ale który nie może aktualnie zmodyfikować zmiennej z tego powodu, że nie spełnia warunku z wiersza , woła metodę wait na obiekcie lock (wiersz ), powodując zwolnienie blokady i przejście wątku do stanu oczekiwania. Natomiast wątek, który właśnie zmodyfikował wartość zmiennej value woła metodę notify (wiersz ), aby obudzić czekający inny wątek.

Poniżej pokazano wynik wykonania programu.

$ scala Synch
Increment(0): new value = 1
Increment(1): new value = 2
Increment(0): new value = 3
Increment(1): new value = 4
Increment(0): new value = 5
Increment(1): new value = 6
Increment(0): new value = 7
Increment(1): new value = 8

Metody notify i wait, należące do metod klasy java.lang.Object, są wywoływane z kodu języka Scala w zwykły sposób. Pewien problem mógłby dotyczyć wywołania metody yield z klasy Thread, gdyby zaszła potrzeba wywołania tej metody z kodu języka Scala. Problem ten związany jest z tym, że yield jest słowem kluczowym w języku Scala, a wobec tego nie jest to prawidłowy identyfikator w tym języku. Na szczęście Scala umożliwia używanie identyfikatorów utworzonych przy pomocy odwrotnych apostrofów, dzięki czemu dostęp do metody yield jest możliwy poprzez zapis `yield`.

scala> Thread.yield()
<console>:1: error: identifier expected but 'yield' found.
Thread.yield()
       ^

scala> Thread.`yield`()

scala> 

Język programowania Scala Wydanie 2. Copyright © Grzegorz Balcerek 2016

Licencja Creative Commons

Ten utwór jest dostępny na licencji Creative Commons Uznanie autorstwa-Na tych samych warunkach 4.0 Międzynarodowe.

Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their respective owners.