2013-10-20 2 views
0

Я пытаюсь выполнить условие взаимоблокировки, но каким-то образом я не могу заставить его работать. Оба потока Thread1 и Thread2 входят в функцию run, но только один из них входит в Sub/Sum в зависимости от того, кто первым запустил run. Пример: если Thread2 вступил в первый запуск, он будет вызывать sub(), а Thread1 никогда не вызывает sum(). Я также добавил время сна, так что Thread2 спит перед вызовом sum(), и Thread1 получает достаточно времени для ввода Sum(), но Thread1 никогда не входит.Выполнение условия взаимоблокировки

public class ExploringThreads { 
     public static void main(String[] args) { 
      // TODO Auto-generated method stub 
      threadexample a1 = new threadexample(); 
      Thread t1 = new Thread(a1, "Thread1"); 
      Thread t2 = new Thread(a1,"Thread2"); 
      t1.start(); 
      t2.start(); 
     } 
    } 
    class threadexample implements Runnable{ 
     public int a = 10; 
     public void run(){ 
      if(Thread.currentThread().getName().equals("Thread1")) 
       sum(); 
      else if(Thread.currentThread().getName().equals("Thread2")) 
       sub(); 
     } 

     public synchronized void sum() 
     { 
      try { 
       Thread.sleep(2000); 
      } catch (InterruptedException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
      System.out.println(Thread.currentThread().getName()+"In Sum"); 
      sub(); 
     } 

     public synchronized void sub() 
     { 
      try { 
       Thread.sleep(2000); 
      } catch (InterruptedException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
      System.out.println(Thread.currentThread().getName()+"In Sub"); 
      sum(); 
     } 
    } 

ответ

1

Это не то, как вы зашли в тупик. На самом деле этот код выглядит довольно безопасным :-) Только один поток вводит sum/sub за раз, потому что вы используете синхронизированный, который синхронизируется на «этом». Существует только одно «это», поэтому обе нити пытаются получить одну и ту же блокировку.

Замыкание происходит, например, когда Thread1 имеет один замок, Thread2 имеет вторую блокировку, а затем Thread1 хотел бы приобрести блокировку Thread2, сохраняя при этом блокировку, и Thread2 хотел бы получить блокировку Thread1, сохраняя при этом блокировку.

Что вы можете сделать, это:

а) добавить 2 объектов для блокировки в классе «threadexample» (кстати классы по соглашению должны начинаться с прописными буквами):

private final Object sumLock = new Object(); 
private final Object subLock = new Object(); 

б) опускать «синхронизирован "в обоих методах sum/sub и вместо этого использовать блок synchronized() {} в каждом из них. Сумма будет синхронизирована (sumLock). {/ * Тело sum отправляется сюда /}, и суб будет синхронизировано (subLock) {/ Тело sub's здесь * /}.

В этом случае Thread1 переходит в sum(), приобретает sumLock и ждет. Thread2 перешел в sub(), приобрел subLock() и подождал. Thread1 проснется, перейдет в sub() и попытается получить subLock, но он удерживается Thread2, поэтому до тех пор, пока Thread2 не выпустит его. В это время Thread2 просыпается, переходит в sum() и пытается получить sumLock, который удерживается Thread1, поэтому Thread2 ждет Thread1, чтобы освободить его.

Ни одна нить не будет идти вперед, поскольку каждый из них ждет другого - у вас есть тупик.

@Edit: да, у вас есть только один экземпляр «threadexample», и как Thread1, так и Thread2 сражаются за блокировку, но когда один из них получает блокировку, он освободит ее после выполнения sum/sub или sub/sum. Например, предположим, что Thread1 является первым и начинает выполнение sum(). Он имеет замок. В этом случае Thread2 не войдет в sub(), поскольку он защищен тем же замком, что и Thread1. Thread1 выполнит sum(), затем sub(), а затем отпустит блокировку -> Thread2 перейдет в sub() и т. Д.

+0

Извините, но Я не понимаю. Это может быть потому, что я новичок в потоковом режиме. По моему пониманию, я сделал только один объект класса threadexample. и Thread1 и Thread2 конкурируют за приобретение блокировки по sum() и sub(). – Bhaskar

1

Если вы действительно хотите создать искусственный мертвый замок, попробуйте следующее:
Thread1 и Thread2 - это два потока, которые хотят получить доступ к одному файлу.

  1. Thread1 начинается, запрашивает замок на File1.docx и спит в течение 2 минут.
  2. Thread2 запускает и совершает исключительную блокировку на File2.docx и теперь хочет получить доступ к File1.docx.
  3. Thread1 просыпается и теперь хочет получить доступ File2.docx который удерживается Thread2

Теперь это круглое состояние ожидания

Простой? =)

+1

Ваш пример неверен. 'Thread2' * заблокирован * до тех пор, пока' Thread' не освобождает свою блокировку, но это не тупик. Условие взаимоблокировки возникает, когда два (или более) потока постоянно блокируются, потому что каждый из них заблокирован, ожидая получения эксклюзивного ресурса, который имеет другой. – Miguel

+0

@Miguel Исправить сейчас? =) Спасибо, что указали это! –

+0

Да, теперь это правильный пример тупика. – Miguel

0

Это рабочий пример «Тупик в действии». В основном то, что вам нужно сделать (и как это обычно происходит в реальном мире) является то, что объект заблокированы в обратном порядке: первый, а второй в одном потоке и б первый, второй в другом:

package stackoverflow; 

public class Deadlock { 

    final static String a = new String("A"); 
    final static String b = new String("B"); 

    public static void main(String[] args) { 

     final Thread abLock = new Thread() { 
      @Override 
      public void run() { 
       lock(a, b); 
      } 
     }; 

     final Thread baLock = new Thread() { 
      @Override 
      public void run() { 
       lock(b, a); 
      } 
     }; 

     abLock.start(); 
     baLock.start(); 

    } 

    static void lock(String first, String second) { 
     synchronized (first) { 
      System.out.println(first); 
      sleep(); 
      synchronized (second) { 
       System.out.println(second); 
      } 
     } 
    } 

    static void sleep() { 
     try { 
      Thread.sleep(500); 
     } catch (InterruptedException e) { 
      throw new RuntimeException(e); 
     } 
    } 

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