2016-08-20 1 views
1

Я пытаюсь научиться использовать wait и уведомлять.Ожидание и уведомление как синхронизация контроллера-менеджера

Мне нужно приложение, которое каждые 10 секунд запрашивает у пользователя, если поток должен продолжать работать или нет. Если нет (пользователь нажимает n), потоку приходится ждать, пока пользователь не напишет «y» на консоли.

Я должен использовать wait и уведомлять, но я не знаю, как это сделать.

Я пытаюсь реализовать ожидание и уведомление без подсказки от пользователя.

Это основной класс, который создает два потока, FolderThread - это поток, который должен работать, и ControlThread - тот, кто должен попросить пользователя, хочет ли он продолжить или нет.

public class MainClass { 

    public static void main(String[] args) throws InterruptedException { 
     FolderThread folder = new FolderThread(); 
     Thread t = new Thread(folder); 
     ControlThread control = new ControlThread(folder); 
     Thread t2 = new Thread(control); 
     t.start(); 
     t2.start(); 
    } 
} 

FolderThread

public class FolderThread implements Runnable { 

    @Override 
    public void run() { 
     while(true) { 
      System.out.println("started"); 
      synchronized(this) { 
       try { 
        this.wait(); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
      } 
     } 
    } 
} 

ControlThread

public class ControlThread implements Runnable { 

    FolderThread folder; 

    public ControlThread (FolderThread folder) { 
     this.folder = folder; 
    } 

    @Override 
    public void run() { 
     synchronized(folder) { 
      folder.notify(); 
     } 
    } 
} 

Проблема заключается в том, что она печатает "Started", а затем он ожидает уведомления о том, никогда не придет! Зачем?

+0

Что происходит если ваш 'ControlThread' идет первым? –

+0

@SotiriosDelimanolis ничего не изменил – untruste

+1

Это не то, что я имею в виду. Выполнение резьбы не является детерминированным. Если, по крайней мере, поток для 'ControlThread' идет первым и выполняет' уведомление ', прежде чем другой поток имеет шанс «подождать», что вы ожидаете? Или даже то, что произойдет, если 'notify' появится после' wait', поток будет возвращаться к 'wait' на следующей итерации. –

ответ

1

Что здесь происходит, так это то, что ваш notify работает, но он не делает ничего, кроме просто «пробуждения» другого потока, пока он не вернется к ожиданию, а затем поток управления будет выполнен, поэтому никогда не «просыпается» снова второй поток.

В принципе, если вы хотите, чтобы не написать пользовательский ввод часть, вы можете моделировать с

Thread.sleep(2000); 
// and then do what would be done if the user had type 'y' 

В этом случае оставшаяся проблема заключается в том, что, когда вы известите другой поток, ничего не делается. Итак, вам нужно 2 вещи:

  1. установить «флаг» где-нибудь, например, передать общий логический поток в оба потока. ваш поток управления должен установить, что логическое значение истина сказать другую нить, что он должен прекратить
  2. читать «флаг» с вашего рабочего потока каждый раз, когда он пробудить вверх, чтобы проверить, должен ли он остановить или не

Таким образом, изменения, вы должны сделать:

  1. Создание AtomicBoolean в основной метод:

    AtomicBoolean flag = new AtomicBoolean(); 
    
  2. Пасс, что Atomic Boolean для конструкторов обоих потоков:

    FolderThread folder = new FolderThread(flag); 
    ControlThread control = new ControlThread(folder, flag); 
    

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

  3. Получить FolderThread, чтобы проверить флаг, когда он просыпается.Заменить while(true) на

    while(flag.get() == false) 
    
  4. Получить ControlThread обновить флаг, когда он хочет, чтобы остановить его:

    flag.set(true); 
    

Стоит отметить, однако, что для реализации простого отношения рабоче-контроллера, где связь ограничена остановкой рабочего потока, вам не нужны wait и notify. Вы можете просто контроллер нить прервать рабочий поток с помощью t.interrupt()

+0

Да, проблема в том, что! ControlThread делал уведомление, но когда FolderThread снова вызывал метод wait, не было ни одного потока, который мог бы вызвать уведомление. Поэтому я использовал while-do в Control-Thread – untruste

0

Это мое решение (с введенной пользователем)

FolderThread

public class FolderThread implements Runnable { 

    @Override 
    public void run() { 

     while(true) { 
      System.out.println("Checking..."); 

      synchronized(this) { 
       try { 
        wait(); 
       } catch (InterruptedException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
       } 
      } 
     } 
    } 
} 

ControlThread

import java.io.BufferedReader; 
import java.io.IOException; 
import java.io.InputStreamReader; 

public class ControlThread implements Runnable { 

    FolderThread folder; 

    public ControlThread (FolderThread folder) { 
     this.folder = folder; 
    } 
    @Override 
    public void run() { 

     try { 
      Thread.sleep(10000); 
     } catch (InterruptedException e1) { 
      // TODO Auto-generated catch block 
      e1.printStackTrace(); 
     } 

     while(true) { 

      InputStreamReader is = new InputStreamReader(System.in); 
      BufferedReader br = new BufferedReader(is); 

      try { 
       do { 
        System.out.println("Continue? y/n"); 

       } 
       while(br.readLine().equals("n")); 
      } catch (IOException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 

      synchronized(folder) { 
       folder.notify(); 
      } 

      try { 
       Thread.sleep(10000); 
      } catch (InterruptedException e1) { 
       // TODO Auto-generated catch block 
       e1.printStackTrace(); 
      } 

     } 
    } 
} 
+0

Это неверно. Попытайтесь снова прочитать ответ. Также см. Учебник оракула по охраняемым блокам. –