2015-05-28 4 views
4

У меня есть простой код, как показано ниже, чтобы проверить тупиковая ситуацияКак срабатывает тупик в приведенном ниже коде?

public class ClassB { 
    public synchronized void fooB(Classs A) throws InterruptedException{ 
     System.out.print("Thread : " + Thread.currentThread().getName()+ " entered to fooB \n"); 
     Thread.sleep(1000); 
     System.out.print("ClassB locked the fooA \n"); 
     A.lastA(); 

    } 

    public synchronized void lastB(){ 
     System.out.print("I am lastB \n"); 
    } 
} 

И Кроме того, я еще один класс называется ClassA:

public class ClassA { 
    public synchronized void fooA(ClassB B) throws InterruptedException{ 
     System.out.print("Thread : " + Thread.currentThread().getName()+ " entered to fooA \n"); 
     Thread.sleep(1000); 
     System.out.print("ClassA locked the fooB \n"); 
     B.lastB(); 
    } 

    public synchronized void lastA(){ 
     System.out.print("I am lastA \n"); 
    }  
} 

Итак, теперь у меня есть еще один код, который вызывает эти классы и вызывает тупиковой, как показано ниже:

public class DeadLockTest implements Runnable { 
    ClassA ca=new ClassA(); 
    ClassB cb=new ClassB(); 

    public DeadLockTest() throws InterruptedException{ 
     new Thread(this).start(); 
     ca.fooA(cb); 
    } 

    public void run() { 
     try { 
      cb.fooB(ca); 
     } catch (InterruptedException ex) { .... 

     } 
    } 
} 

Как вы можете видеть первые резьбовые замки fooB с помощью ca.fooA (Cb), а вторая нить блокирует fooA, используя cb.fooB (ca) и Никто не блокирует методы lastA и lastB. Это означает, что эти методы должны быть доступны, но они недоступны. Зачем? Нити только блокируют fooA и fooB. Итак, почему, например, первый поток не может использовать lastB(), а второй не имеет доступа к lastA(), в то время как блокировка этих двух методов отсутствует?

ответ

11

При использовании по методу ключевое слово synchronized неявно блокируется на this - ну, на мониторе, связанном с this. Объекты имеют мониторы; методов нет. Таким образом, монитор используется для fooA(): тот же монитор используется на lastA(). Вот почему вы зашли в тупик.

Пожалуйста, прочитайте на synchronized, прежде чем идти дальше ...

+3

Действительно, это скорее намерение, что все синхронизированные методы данного класса являются исключительными для данного объекта. Это победит цель, если один поток может быть «внутри» модифицирующего метода, тогда как другой поток находится внутри некоторого метода только для чтения. Я согласен с dcsohl. Вы не получили его, пока не получите это. Это «большая идея» в основе разработки параллельных программ с использованием взаимных исключений (mutex). – Persixty

3

Это выглядит довольно прямо вперед. Это типичный сценарий совместного использования ресурсов. Потребности B для продолжения, а B - для продолжения.

Замки:

Thread 1 -> ClassB -> ClassA 
Thread Main -> ClassA -> ClassB 

Обработка заказа:

  1. От Thread Main, вы начинаете новую нить нитяным
  2. нитяным получает блокировку для ClassB
  3. Thread Главная получает блокировку для ClassA
  4. Поток А запрос на блокировку, и блоков, для блокировки на ClassA
  5. Thread Главная запрос на блокировку, и блоков, для замок на ClassB
0

Вы синхронизируете методы, поэтому объект блокировки является объективистским t в каждом случае (ca и cb).

Когда поток вызывает cb.fooB(ca), он захватывает объект блокировки cb.

Тогда основная нить вызывает ca.fooA(cb) и поэтому захватывает объект блокировки ca.

Но, fooA метод вызывает cb.lastB() в основном потоке, и этот метод также синхронизирован, поэтому основной поток пытается захватить блокировку cb, только чтобы найти, что другой поток уже заблокирован, поэтому он должен ждать ,

В то же время, другой поток называется cb.fooB(ca), который в свою очередь вызывает ca.lastA(), поэтому пытается захватить замок на ок, только чтобы обнаружить, что основной поток уже имеет блокировку, поэтому он тоже должен ждать.

Результат: каждый поток имеет замок, другой должен действовать, поэтому они ждут друг друга. Тупик.