2015-08-06 2 views
2

Я работаю над приложением и должен иметь возможность приостанавливать среднюю обработку основного потока. Моя идея состояла в том, чтобы иметь три потока: основные, поток прослушивания для ввода (либо остановить или GO команд), а затем другой поток, чтобы вызвать главное, чтобы остановить:Как я могу приостановить Главный поток из отдельного потока?

public static boolean stopped = false; 
public static void main (String[] args){ 

    Thread main = Thread.currentThread(); 

    Runnable t1 = new Runnable() { 
     public void run() { 
      while(true){ 
       Scanner s = new Scanner(System.in); 
       // wait for command 
       String in = s.nextLine(); 
       if(in.equals("STOP")){ 
        synchronized(main){ 
         stopped = true; 
         //create new thread to make main wait 
         Runnable t2 = new Runnable() { 
          public void run(){ 
           synchronized(main){ 
            while(stopped){ 
             main.wait(); 
            } 
           } 
          } 
         }; 
         Thread th2 = new Thread(t2); 
         th2.start(); 
        } 
       } 
       if (in.equals("GO")){ 
        synchronized(main){ 
         stopped = false; 
         main.notifyAll(); 
        } 
       } 
      } 
     } 
    }; 

    Thread th1 = new Thread(t1); 
    th1.start(); 

    while(true){ 
     synchronized(main){ 
      // Do lots of stuff that needs to pause when user enters STOP 
      System.out.println("Main is running"); 
      Thread.sleep(5000); 
     } 

    }  
} 
} 

В настоящее время основная продолжается через петлю, даже после остановки дается команда. Есть ли способ заблокировать главный, пока другой поток не освободит его, не делая в основном wait()?

+0

Использование 'notify' или 'notifyAll' - лучший подход здесь. Если вы хотите только уведомлять поток A из потока B, вам необходимо передать ссылку ('Thread.currentThread()'). –

+1

Попробуйте прочитать Javadoc метода Object.wait(). Он не делает то, что вы думаете, но может быть частью решения. – meriton

+0

Как насчет того, чтобы не пытаться заблокировать основной поток, а вместо этого использовать основной поток для прослушивания ввода? – Aify

ответ

3

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

Например, вы можете создать рабочий поток и позволить основному потоку программы управлять командами и делегировать инструкции своему работнику. Метод process - это инкрементный объем работы, такой как чтение одной строки большого файла. Например, пусть это будет вашей рабочей задачей:

public abstract class Worker implements Runnable { 
    private final Object lock = new Object(); 
    private final AtomicBoolean shouldWait = new AtomicBoolean(); 

    protected abstract boolean processingIsComplete(); 
    protected abstract void process(); 
    protected abstract void cleanUpResources(); 

    public Object getLock() { 
    return lock; 
    } 

    public void disable() { 
    shouldWait.set(false); 
    } 

    public void enable() { 
    shouldWait.set(true); 
    } 

    @Override 
    public void run() { 
    try { 
     while(!processingIsComplete()) { 
     while(!shouldWait.get()) { 
      synchronized(lock); 
      lock.wait(); 
      } 
     } 
     process(); 
     } 
    } catch(InterruptedException e) { 
     System.out.println("Worker thread stopped"); 
    } finally { 
     cleanUpResources(); 
    } 
    } 
} 

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

public static void main (String[] args) throws Exception { 
    Worker worker = new WorkerImpl(/* whatever args are needed */); 
    Thread workerThread = new Thread(worker); 
    System.out.println("Starting process..."); 

    worker.start(); 
    Scanner sc = new Scanner(System.in); 

    while(true) { 
    System.out.printn("Please enter command: "); 
    String command = sc.nextLine(); 
    if("END".equals(command)) { 
     System.out.println("Terminating program... "); 
     workerThread.interrupt(); 
     break; 
    } else if ("GO".equals(command)) { 
     synchronized(worker.getLock()) { 
     System.out.println("Continuing worker thread... "); 
     worker.enable(); 
     worker.getLock().notifyAll(); 
     } 
    } else if ("STOP".equals(command)) { 
     synchronized(worker.getLock()) { 
     System.out.println("Stopping worker thread "); 
     worker.disable(); 
     worker.getLock().notifyAll(); 
     } 
    } else { 
     printCommandHelp(); 
    } 
    } 
}; 

Дальнейшее чтение: How to use wait and notify in Java?

+0

Это не дает поведения, которое я искал. В вашем примере я хочу иметь возможность приостанавливать рабочий поток, пока он произвольно находится внутри процесса(). Ваше решение ждет, когда рабочий завершит процесс(), а затем проверяет, должен ли он ждать. – Tim

+0

Это делает, если вы реализуете процесс в небольших кусках, например. Одна строка файла за раз. Это не должно быть трудно адаптировать, но я не могу, потому что я ничего не знаю о реализации Работника – durron597

+0

Это объясняет это, спасибо – Tim

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