简体   繁体   中英

How can I pause Main thread from a separate thread?

I am working on an application and need to be able to pause the main thread mid-processing. My idea was to have three threads: main, a thread listening for input (either STOP or GO commands) and then another thread to cause the main to stop:

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);
        }

    }       
}
}

Currently main continues through its loop even after the STOP command is given. Is there a way to lock main until another thread releases it without having to do the wait() in main?

You don't want to structure it the way you're doing it. You don't want the thread to stop at an arbitrary point; that could cause problems when trying to resume it. Instead, give the thread clear stopping points.

For example, you could create a worker thread, and let the program's main thread manage the commands and delegate instructions to your worker. The process method is an incremental amount of work, such as reading one line of a large file. For example, let this be your worker task:

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();
    }
  }
}

Then, modify / subclass worker to actually do the processing work. Then, in your main class, you can turn on and off your worker as needed. This is just a skeleton, obviously you could refactor the behavior into multiple methods, add other controls such as reading the status of the worker thread, etc.:

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();
    }
  }
};

Further reading: How to use wait and notify in Java?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM