Java.Multithreading.What is a livelock?

A livelock is similar to a deadlock, but with a twist:

Threads keep changing their state in response to each other, but make no real progress.

They’re not blocked (like in a deadlock), but they’re too polite — constantly reacting to each other, leading to an endless loop of “after you, no, after you…”

🧠 Deadlock vs. Livelock

AspectDeadlockLivelock
Threads stateBlocked (waiting for a lock)Active (running, retrying)
ProgressNoneNone
CauseCircular waitConstant mutual reactions
Looks likeFreezeEndless spinning without progress

🔄 Livelock Analogy

Two people meet in a hallway:

  • Person A steps to the left to let B pass.
  • Person B also steps to the left.
  • Then both step to the right. Still blocked.
  • They keep stepping back and forth — forever.
class Spoon {
    private Diner owner;

    public Spoon(Diner d) {
        this.owner = d;
    }

    public synchronized void use() {
        System.out.println(owner.name + " is eating with the spoon.");
    }

    public Diner getOwner() {
        return owner;
    }

    public void setOwner(Diner d) {
        this.owner = d;
    }
}

class Diner {
    public String name;
    public boolean isHungry = true;

    public Diner(String name) {
        this.name = name;
    }

    public void eatWith(Spoon spoon, Diner spouse) {
        while (isHungry) {
            // Check if it's this diner’s turn
            if (spoon.getOwner() != this) {
                try { Thread.sleep(1); } catch (InterruptedException ignored) {}
                continue;
            }

            // Be polite: wait for spouse
            if (spouse.isHungry) {
                System.out.println(name + ": You eat first my dear " + spouse.name);
                spoon.setOwner(spouse);
                continue;
            }

            // Eat!
            spoon.use();
            isHungry = false;
            System.out.println(name + ": I'm done eating.");
            spoon.setOwner(spouse);
        }
    }
}

public class LivelockExample {
    public static void main(String[] args) {
        final Diner husband = new Diner("Husband");
        final Diner wife = new Diner("Wife");
        final Spoon spoon = new Spoon(husband);

        new Thread(() -> husband.eatWith(spoon, wife)).start();
        new Thread(() -> wife.eatWith(spoon, husband)).start();
    }
}

💡 What’s Happening?

  • Both threads run.
  • Each sees the other is hungry and gives up the spoon.
  • Neither eats.
  • They keep passing the spoon back and forth — forever.

→ That’s livelock.

How to Avoid Livelock

  • Use backoff algorithms (e.g., random delay before retrying).
  • Add timeout conditions or a maximum retry limit.
  • Don’t design overly “polite” behavior — be assertive with shared resources.
This entry was posted in Без рубрики. Bookmark the permalink.