Пример из книги Герберта Шилдта
package testpack;

class Deadlock implements Runnable {

    class A {
        synchronized void foo(B b) {
            String name = Thread.currentThread().getName();

            System.out.println(name + " entered A.foo");

            try {
                Thread.sleep(1000);
            } catch(Exception e) {
                System.out.println("A Interrupted");
            }

            System.out.println(name + " trying to call B.last()");
            b.last();
        }

        synchronized void last() {
            System.out.println("Inside A.last");
        }
    }

    class B {
        synchronized void bar(A a) {
            String name = Thread.currentThread().getName();
            System.out.println(name + " entered B.bar");

            try {
                Thread.sleep(1000);
            } catch(Exception e) {
                System.out.println("B Interrupted");
            }

            System.out.println(name + " trying to call A.last()");
            a.last();
        }

        synchronized void last() {
            System.out.println("Inside A.last");
        }
    }

        A a = new A();
        B b = new B();

        Deadlock() {
            Thread.currentThread().setName("MainThread");
            Thread t = new Thread(this, "RacingThread");
            t.start();

            a.foo(b); // get lock on a in this thread.
            System.out.println("Back in main thread");
        }

        public void run() {
            b.bar(a); // get lock on b in other thread.
            System.out.println("Back in other thread");
        }

        public static void main(String args[]) {
            new Deadlock();
        }
    }
Не понимаю почему здесь получается взаимная блокировка. Один поток заходит в foo, второй в bar. И, насколько я понимаю, здесь могу уже ошибаться тк не слишком силен в данной теме, foo блокирует B b обьект, а bar блокирует A a. И вот когда код доходит до выполнения last() метода я не понимаю, почему synchronized void bar(A a) { //..// a.last(); } не может выполнить его, метод bar ведь сам и удерживает мьютекс обьекта а, который и требуется для выполнения a.last() метода. Ну и соответственно для B b обьекта.