Dead lock (взаимная блокировка)

Dead lock (взаимная блокировка)

Пусть тестировщик и программист работают над двумя версиями приложения: для Android и iPhone. Приложение для Android находится на стадии тестирования, по завершении которого баги должны быть устранены программистом. Приложение для iPhone находится на стадии разработки, после чего должно быть протестировано тестировщиком.
И вот Android-приложение окончило фазу тестирование и требует устранения багов программистом. В это же время iPhone-приложение завершило стадию разработки и теперь требует тестирования. Однако, менеджер этих двух проектов не хочет отпускать ресурсы, пока каждый проект не будет закончен.
Получается, что каждый проект ждёт завершения другого проекта. Получили взаимную блокировку порядка синхронизации.


abstract class ITishnik {
    String name;

    ITishnik(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}


// программист
class Developer extends ITishnik {

    Developer(String name) {
        super(name);
    }

    void code() {
        System.out.println("Developer is coding...");
    }

    void fixBugs() {
        System.out.println("Developer is fixing bugs...");
    }
}


// тестировщик
class Tester extends ITishnik {

    Tester(String name) {
        super(name);
    }

    void testApp() {
        System.out.println("Tester is testing...");
    }
}


abstract class Application extends Thread {
    Developer developer;
    Tester tester;

    public Application(Developer developer, Tester tester) {
        this.developer = developer;
        this.tester = tester;
    }

    protected void sleepThread(String lockname) {
        try {
            System.out.println(this.getName() + " acqured " + lockname);
            Thread.sleep((long) Math.random() * 1000L);
        } catch (InterruptedException e) {
            e.printStackTrace(System.out);
        }
    }
}


// приложение для Android
class AndroidApp extends Application {

    public AndroidApp(Developer developer, Tester tester) {
        super(developer, tester);
        this.setName("AndroidApp");
    }

    @Override
    public void run() {
        synchronized (tester) {
            sleepThread(tester.getName());
            synchronized (developer) {
                tester.testApp(); // тестирование приложения
                developer.fixBugs(); // исправление багов
            }
        }
    }
}


// приложение для iPhone
class iPhoneApp extends Application {

    public iPhoneApp(Developer developer, Tester tester) {
        super(developer, tester);
        this.setName("iPhoneApp");
    }

    @Override
    public void run() {
        synchronized (developer) {
            sleepThread(developer.getName());
            synchronized (tester) {
                developer.code(); // разработка приложения
                tester.testApp(); // тестирование
            }
        }
    }
}


public static void main(String[] args) {
        Developer developer = new Developer("Developer");
        Tester tester = new Tester("Tester");

        AndroidApp android = new AndroidApp(developer, tester);
        iPhoneApp iPhone = new iPhoneApp(developer, tester);

        android.start();
        iPhone.start();
}
Вывод:


/*
AndroidApp acqured Tester
iPhoneApp acqured Developer
*/
Многопоточность