Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java: Общие вопросы > deadlock


Автор: Pawl 19.3.2011, 20:17
Доброго времени суток!
Так получилось, что я должен объяснить пример deadlok'a, используя синхронизированные методы.
Написал для этого простенькую программку, прикинул, как ее пояснить и подумал, что лучше вначале спросить знающих людей, а правильно ли я все сам понимаю? Поскольку поблизости таковых не оказалось, прошу Вас посмотреть, насколько верны и понятны мои пояснения. Привожу сначала код, а затем то, как я его собираюсь пояснять.
Код

class Thread_1 extends Thread {
    Thread_2 t2;

    public void iniz(Thread_2 t2) {
        this.t2 = t2;
    }

    public synchronized void run() {
        System.out.println("Thread 1: locked");
        t2.run(); 
        System.out.println("Thread 1: made free");
    }
}

class Thread_2 extends Thread {
    Thread_1 t1;
    
    public void iniz(Thread_1 t1) {
        this.t1 = t1;
    }

    public synchronized void run() {     
        System.out.println("Thread 2: locked");
        t1.run();
        System.out.println("Thread 2: made free");     
    }
}

public class Deadlock {
    public static void main(String[] args) {
        Thread_1 t1 = new Thread_1();
        Thread_2 t2 = new Thread_2();
        t1.iniz(t2);
        t2.iniz(t1);
        
        t1.start(); // тут основнй поток на объекте класса Thread_1 (т. е. на t1) вызывает синхронизированный метод run,
                 // создавая новый поток, а t1 блокируется основным потоком.
                        
        t2.start(); // тут основнй поток на объекте класса Thread_2 (т. е. на t2) вызывает синхронизированный метод run,
                 // создавая новый поток, а 2 блокируется основным потоком.
    }
}

Пояснение:
По команде t1.start() основной поток программы автоматически запускает синхронизированный метод run объекта t1. Тем самым создается новый поток, а объект t1 блокируется основным потоком. Тоже происходит по команде t2.start() с объектом t2. На объекте t1 из метода run делается попытка доступа к объекту t2, который, уже заблокирован основным потоком. Поэтому попытка не удается, а метод run() объекта t1 останавливается и ждет разблокировки t2. Сам t1 остается заблокированным и разблокируется только тогда, когда его метод run завершит свою работу. 
Из t2, в свою очередь, делается попытка обращения к t1, тоже безуспешная, т. к. t1 также заблокирован основным потоком. Поэтому метод run() объекта t2 не может завершиться и t2 остается заблокированным.

Спасибо заранее за консультацию!

Автор: Pawl 22.3.2011, 22:39
Товарисчи, а-у! smile

Автор: Temdegon 23.3.2011, 01:24
Честно признаюсь, разбиратсья лень.
Вот линк на отличную статью про синхронизацию потоков.
http://skipy.ru/technics/synchronization.html
Очень доступно написано. Как раз там есть пример дэдлока. 
Если статья вам поможет - ее автор, Skipy, тоже на этом форуме, не забудьте ему плюсик начислить =)

Автор: Pawl 23.3.2011, 08:49
Цитата

Честно признаюсь, разбиратсья лень.

Согласен, уважительная причина, как я ее понимаю smile ! Как говориться лень - двигатель прогресса! А за ссылку на статью спасибо, почитаю обязательно!

Автор: jk1 23.3.2011, 13:14
1.
Цитата

 Тем самым создается новый поток, а объект t1 блокируется основным потоком. 


Почему основным? Владельцем монитора будет поток t1. Основной поток, который постоянно упоминается в описании, в блокировке не учавствует вовсе, deadlock происходит между потоками t1 и t2.

2. Зачем сделано два практически одинаковых класса? Они отличаются только константой.

3. Кроме того, непонятно зачем под инициализацию изобретать отдельный метод, для этого же конструктор есть. Но это так, мелочь.

Автор: Pawl 24.3.2011, 09:27
Спасибо за конструктивный ответ!

Цитата(jk1 @  23.3.2011,  13:14 Найти цитируемый пост)
Почему основным? Владельцем монитора будет поток t1.

Вообще-то я читал, что монитор на объект захватывает поток, который вызвал на этом объекте синхронизированный метод. Тут ведь основной поток вызывает синхронизированный метод run на объектах  t1 и t2, значит он их и блокирует, нет?
Цитата

Кроме того, непонятно зачем под инициализацию изобретать отдельный метод, для этого же конструктор есть

Просто в t1 надо было как-то передать t2 и наоборот. И если бы я написал что-то вроде
Код

Thread_1 t1 = new Thread_1(t2);
Thread_2 t2 = new Thread_1(t1);

компилятор меня бы наверное не понял.

Автор: jk1 25.3.2011, 10:38
Цитата

компилятор меня бы наверное не понял.


 smile да, это я проглядел

Цитата

Вообще-то я читал, что монитор на объект захватывает поток, который вызвал на этом объекте синхронизированный метод. Тут ведь основной поток вызывает синхронизированный метод run на объектах  t1 и t2, значит он их и блокирует, нет?


Все правильно Вы читали, вот только основной поток вызывает не метод run(), а метод start(). Start() в свою очередь запускает новый поток, и уже этот новый поток вызовет синхронизированный метод run().

Автор: Pawl 25.3.2011, 21:34
Цитата

основной поток вызывает не метод run(), а метод start(). Start() в свою очередь запускает новый поток, и уже этот новый поток вызовет синхронизированный метод run().

Действительно, написано же не t1.run(), a t1.start()! Спасибо огромное, помогли разобраться, тему закрываю.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)