Примечание: Проблема, которую я решаю, имеет только образовательные цели, я знаю, что абстракция, которую я хочу создать, подвержена ошибкам и т. Д. ... Мне не нужно быстрое решение , Мне нужно объяснение.SyncVar производитель/потребительские потоки в scala
В книге я читал есть упражнение, которое говорит, что мне нужно реализовать SyncVar, которая имеет следующий интерфейс:
class SyncVar[T] {
def get(): T = ???
def put(x: T): Unit = ???
}
Мой комментарий: Хорошо кажется понятным, нужно немного синхронизации переменной, что я могу положите.
Объект SyncVar используется для обмена значениями между двумя или более потоками. При создании объекта SyncVar пуст:
° Вызов GET бросает исключение
° Вызов положить добавляет значение объекта SyncVar После значение добавляется к объекту SyncVar, можно сказать, что это непусто:
° Вызов прибудет возвращает текущее значение, и изменяет состояние опустошить
° Вызов положить Выдает исключение
Мои мысли: Это переменная, которая выдает исключение при пустом значении при вызове get или put, когда у нас есть значение, когда мы вызываем get, оно очищает предыдущее значение. Похоже, мне нужно использовать опцию.
Так я обеспечиваю следующую реализацию:
class SyncVar[T] {
var value: Option[T] = None
def get(): T = value match {
case Some(t) => this.synchronized {
value = None
t
}
case None => throw new IllegalArgumentException("error get")
}
def put(x: T): Unit = this.synchronized{
value match {
case Some(t) => throw new IllegalArgumentException("error put")
case None => value = Some(x)
}
}
def isEmpty = value.isEmpty
def nonEmpty = value.nonEmpty
}
Мой комментарий: Синхронно, ссылающегося на месте и получить, также имеют IsEmpty и непустые
Следующая задача заставляет меня путать: Объект SyncVar из предыдущего упражнения может быть громоздким для использования, из-за исключений, когда объект SyncVar находится в недопустимом состоянии. Внесите пару методов isEmpty и nonEmpty в объект SyncVar. Затем реализует поток производителя, который переносит диапазон чисел 0 до 15 на потребительский поток, который их печатает.
Как я понимаю, мне нужно две темы:
//producer thread that produces numbers from 1 to 15
val producerThread = thread{
for (i <- 0 until 15){
println(s"$i")
if (syncVar.isEmpty) {
println(s"put $i")
syncVar.put(i)
}
}
}
//consumer that prints value from 0 to 15
val consumerThread = thread{
while (true) {
if (syncVar.nonEmpty) println(s"get ${syncVar.get()}")
}
}
Вопрос: Но этот код вызвано недетерминизма, поэтому он имеет различный результат каждый раз, в то время как мне нужно печатать цифры от 1 до 15 (в правильном порядке). Не могли бы вы объяснить мне, что не так с моим решением?
Да, вы правы, проблема заключается в том, что я не могу гарантировать, что 'get' будет называться по' 'consumerThread' после put', даже когда я применяю синхронизации на 'put' и' get'. Как я могу гарантировать, что после того, как потребительский поток 'put' вызовет' get' и установит значение 'None? –
Подсказка: вам нужно _wait_ в 'producerThread', пока' syncVar' не будет пустым (и наоборот в 'consumerThread'). Как вы можете использовать внутренний цикл для этого? –
Спасибо за подсказки, вместо того, чтобы решить это для меня :) –