Deadlock - горутины навсегда заблокированы, каждая ждет ресурс, удерживаемый другой. Программа зависает, CPU не потребляется.
Livelock - горутины активны и потребляют CPU, но бесконечно реагируют друг на друга без продвижения. Как два человека в коридоре, которые одновременно уступают друг другу дорогу в одну и ту же сторону.
// Пример livelock: два "вежливых" воркера
// Каждый уступает ресурс другому при конфликте
func worker(id int, res1, res2 *sync.Mutex) {
for {
res1.Lock()
if !res2.TryLock() {
res1.Unlock() // "уступаю!"
continue // попробую снова - livelock!
}
// работа...
res2.Unlock()
res1.Unlock()
return
}
}
Решения livelock:
Livelock сложнее диагностировать, чем deadlock: программа не зависает, но потребляет CPU без результата. Go runtime обнаруживает deadlock (fatal error), но не livelock.