Clojure STM (dosync) x блок синхронизации Java - PullRequest
10 голосов
/ 27 августа 2010

В чем разница между подходом Clojure STM (dosync) и блоком синхронизации Java?

Я читаю приведенный ниже код из задачи "Спящий цирюльник".(http://www.bestinclass.dk/index.clj/2009/09/scala-vs-clojure-round-2-concurrency.html)

(defn the-shop [a]  
  (print "[k] entering shop" a)  
  (dosync     
    (if (< (count @queue) seats)  
      (alter queue conj a)  
      (print "[s] turning away customer" a))))

Чтобы избежать условий гонки, используется dosync, поэтому я спрашиваю себя «В чем отличие (STM) от блока синхронизации Java»? Будет ли он блокировать этот критический код?

Заранее спасибо! Дантас

Ответы [ 4 ]

19 голосов
/ 27 августа 2010

dosync и synchronized предоставляют доступ к совершенно разным абстракциям параллелизма.

synchronized - это способ получения и снятия блокировок.Когда поток входит в блок synchronized, он пытается получить соответствующую блокировку;если блокировка в настоящий момент удерживается другим потоком, текущий поток блокируется и ожидает его освобождения.Это приводит к определенным проблемам, таким как риск тупика.Блокировка снимается, когда поток покидает блок synchronized.

dosync отмечает блок кода, который должен быть запущен в транзакции.Транзакции в Clojure являются способом координации изменений в Refs (объекты, созданные с помощью функции ref);если вам нужен какой-то код, чтобы иметь согласованное представление некоторых частей изменяемого состояния в Clojure - и, возможно, изменить их - вы помещаете их в Refs и выполняете свой код в транзакции.

Транзакция имеет интересныйсвойство, которое будет перезапущено, если по какой-либо причине не сможет зафиксировать, вплоть до определенного максимального числа повторов (в настоящее время жестко задано значение 10000).Среди возможных причин невозможности совершения транзакции - неспособность получить единообразное представление о мире (на самом деле, соответствующие ссылки - есть «адаптивная история»), которая делает эту проблему менее сложной, чем может показатьсяПервый взгляд);одновременные изменения, сделанные другими транзакциями;и т. д.

Транзакция не рискует быть заблокированной (если только программист не изо всех сил вводит тупик, не связанный с системой STM через взаимодействие Java);livelock, с другой стороны, является определенной возможностью, хотя и не очень вероятной.В общем, многие - хотя и не все!- интуиции, которые программисты связывают с транзакциями базы данных, действительны в контексте систем STM, включая систему Clojure.

STM - огромная тема;Отличным ресурсом для изучения STM Clojure является статья Марка Фолькмана Software Transactional Memory .Он очень углублен в обсуждение STM Clojure в его заключительных разделах, но его начало может послужить хорошим вводным чтением.

Что касается приведенного вами фрагмента, на самом деле это не то, что вы обычно хотели бы эмулировать в производственном коде., поскольку dosync блоки почти всегда должны быть без побочных эффектов;print здесь может быть полезен для демонстрации внутренней работы STM, но если вы хотите, чтобы транзакция вызывала побочные эффекты в реальном коде, вам нужно, чтобы она порождала Clojure Agent для этой цели (которая только выполняла бы свою задачуесли транзакция успешно зафиксирована).

3 голосов
/ 03 ноября 2010

Просто, чтобы дать полную картину для тех, кто ищет, у Clojure есть synchronized аналог.Это полезно, когда для взаимодействия нужно работать с не-безопасными типами Java.

(locking x & body)
3 голосов
/ 27 августа 2010

Кроме того, в ответ на превосходный ответ Михала, с транзакциями STM, читает всегда возвращает вам замороженное значение в начале транзакции и не нужно ждать завершения любой текущей транзакции.

0 голосов
/ 10 апреля 2016

основное различие заключается в следующем

Clojure STM поддерживает оптимистичный параллелизм, тогда как синхронизированный JAVA равен pessimist

Clojure STM не получает блокировку до тех пор, покабольше чем одна нить.если изменяемое состояние обновляется другим потоком, то операция внутри dosync повторяется.Кроме того, dosync является обязательным для изменяемых состояний.В отличие от JAVA, Clojure генерирует исключение нелегальное состояние при отсутствии dosync.

...