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 для этой цели (которая только выполняла бы свою задачуесли транзакция успешно зафиксирована).