2014-11-04 3 views
2

Ниже код, который я написал для тупика, но для небольшого кода «для цикла» не заходит в тупик, а когда я держу «за цикл» до 10, тогда происходит тупик.Почему взаимоблокировка происходит в моем коде?

Может кто-нибудь объяснить, почему он проявляет такое поведение?

public class CustomerUpdateDeadloackThread { 

    public static void main(String[] args) { 

     Customer cstmr = new Customer("Peter"); 
     Address adrs = new Address("B-232, Bangalore"); 


    // For loop till 3 is not showing deadlock. 
    for (int i=0; i<10;i++){ 
     new Thread(new TagObjectsToEachOther(cstmr, adrs)).start(); 
     new Thread(new TagObjectsToEachOther(adrs, cstmr)).start(); 
    } 


    } 
} 

interface CustomerUpdater { 

    public boolean update(Object obj); 

} 

class TagObjectsToEachOther implements Runnable { 
    CustomerUpdater taskItem; 
    Object objToUpdateWith; 

    public TagObjectsToEachOther(CustomerUpdater cspdtr, Object obj2) { 
     this.taskItem = cspdtr; 
     this.objToUpdateWith = obj2; 
    } 

    @Override 
    public void run() { 
     taskItem.update(objToUpdateWith); 
     System.out.println(" Task done :" + Thread.currentThread().getName()); 
    } 

} 

class Address implements CustomerUpdater { 

    String address; 
    Customer customer; 

    public Address(String addrs) { 
     this.address = addrs; 
    } 

    @Override 
    public boolean update(Object cstmr) { 
     synchronized (this) { 
      synchronized ((Customer) cstmr) { 
       try { 
        this.customer = (Customer) cstmr; 
        Thread.sleep(2000); // or else do some other work here 
       } catch (CustomerUpdateFailureException e) { 
        e.getCause(); 
        return false; 
       } catch (InterruptedException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
       } 
       return true; 
      } 
     } 
    } 

} 

class Customer implements CustomerUpdater { 

    String name; 
    Address address; 

    public Customer(String nm) { 
     this.name = nm; 
    } 

    @Override 
    public boolean update(Object adrs) { 
     synchronized (this) { 
      synchronized ((Address) adrs) { 
       try { 
        this.address = (Address) adrs; 
        Thread.sleep(2000); // or else do some other work here 
       } catch (CustomerUpdateFailureException e) { 
        e.getCause(); 
        return false; 
       } catch (InterruptedException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
       } 
       return true; 
      } 
     } 
    } 

} 

class CustomerUpdateFailureException extends RuntimeException { 

    private static final long serialVersionUID = 1L; 

    @Override 
    public String getMessage() { 

     return "Uncompitable update"; 
    } 

} 
+0

У вас есть программа, которая в основном предназначена для тупика. Вам было бы проще сказать, почему вы не должны заходить в тупик. –

+0

@ Peter Lawrey: На самом деле мне нужен код для тупика. – Rohit

ответ

6

Вы только собираетесь получить в тупик, если один из ваших потоков получает один монитор и другой поток получает другой монитор перед первой поток получает второй монитор. Чем больше потоков вы получаете мониторы на двух объектах, тем больше вероятность того, что один из них получит только один замок и будет предварительно упущен, прежде чем получит шанс получить второй монитор.

Другими словами, это прекрасно, и просто вызывает ожидание:

Thread A    Thread B 
    Lock X 
    Lock Y 
         Lock Y // Blocks (temporary) 
    Sleep 
         Lock X 
         Sleep 

В то время как это приводит к тупиковой:

Thread A    Thread B 
    Lock X 
         Lock Y 
    Lock Y // Blocks (deadlock) 
         Lock X // Blocks (deadlock) 

При перемещении Thread.sleep(2000) вызов между вашими двумя synchronized заявления (в обоих методах), то вы почти гарантированно получите тупик, без любой зацикливания на верхнем уровне.

+0

Спасибо, Джон Скит. На самом деле без сна тупик прерывался. – Rohit

+1

@Rohan: Да, было бы. Добавление сна просто позволяет вам «ободрить» тупик, сделав рискованный кусок кода (где поток принадлежит только одному монитору) занимает больше времени. –

Смежные вопросы