Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fix this deadlock code in java? [closed]

Tags:

java

deadlock

I got this deadlock sample codes from oracle.

class Thread_Test {
    static class Friend {
        private final String name;
        public Friend(String name) {
            this.name = name;
        }
        public String getName() {
            return this.name;
        }
       public synchronized void bow(Friend bower) {
            System.out.format("%s: %s" + "  has bowed to me!%n", this.name, bower.getName());

            bower.bowBack(this);
        }
        public synchronized void bowBack(Friend bower) {
            System.out.format("%s: %s" + " has bowed back to me!%n", this.name, bower.getName());
        }
    }

    public static void main(String[] args) {
        final Friend alphonse = new Friend("Alphonse");
        final Friend gaston = new Friend("Gaston");
        new Thread(new Runnable() {
            public void run() { alphonse.bow(gaston); }
        }).start();
        new Thread(new Runnable() {
            public void run() { gaston.bow(alphonse); }
        }).start();
    }
}

If I change function bow like below, I can resolve the deadlock issue.

public void bow(Friend bower) {
    synchronized(this) {
        System.out.format("%s: %s" + "  has bowed to me!%n", this.name, bower.getName());
    }
    bower.bowBack(this);
}

Can I use other approaches to resolve this deadlock issue.

Especially, I wonder that Thread.sleep() can be a solution for deadlock and how I can use it.

Could you let me know about the possibility of Thread.sleep() and other approaches?

Thanks alot

like image 567
500004dolkong Avatar asked May 18 '26 07:05

500004dolkong


2 Answers

You need to lock on 2 objects at once (Let's call them A and B). here is a nice explaination of what might happen. To fix that, you could try to always lock in same order:

static class Friend {
    private static int idCounter;
    private final int id;
    private final String name;

    public Friend(String name) {
        this.name = name;
        id = idCounter++;
    }
    public String getName() {
        return this.name;
    }

    public void bow(Friend bower) {
        Friend first, second;
        if(bower.id > id) {
            first = this;
            second = bower;
        } else {
            first = bower;
            second = this;
        }
        synchronized(first) {
            synchronized(second) {
                System.out.format("%s: %s has bowed to me!%n", this.name,bower.getName());

                bower.bowBack(this);
            }
        }
    }
    public synchronized void bowBack(Friend bower) {
        System.out.format("%s: %s has bowed back to me!%n", this.name, bower.getName());
    }
}

Here the Friend with lower id gets locked first, so the deadlock now should't happen.

like image 64
kajacx Avatar answered May 19 '26 19:05

kajacx


The deadlock is occurring because the following method calls occur:

  • Alphonse calls bow(), getting Alphonse/bow lock
  • Gaston calls bow(), getting Gaston/bow lock
  • Alphonse tells Gaston to bowBack(), and waits for Gaston to complete that action
  • Gaston tells Alphonse to bowBack(), and waits for Alphonse to complete that action.
  • thus, both are waiting for the other to finish bowBack() in order to finish their bow(), but cannot start their own bowBack() until they finish bow(). Deadlock.

The reason your solution works is that the bowBack(this) call is outside of the synchronized block.

Smart use of Locks can both demonstrate more clearly why and exactly where deadlock is occurring, and can prevent it. Java's Semaphore class is a nice one to look into.

To actually fix it (prevent deadlock but keep it thread safe), you have to expand on the problem - what should happen when Gaston is waiting for Alphonse to finish bow() to execute his own bow(), but Alphonse needs Gason to execute a bowBack() to finish? One sensible solution is for Gaston to give up on executing bow() when the call to bowBack() comes and just execute bowBack(), but it all depends on what problem you're trying to solve.

like image 38
Mshnik Avatar answered May 19 '26 21:05

Mshnik