简体   繁体   中英

How one thread can wait until another one finishes to fire some actions

As shown below in the code, I am loading a heavy file on a worker thread fileThread , and while that thread loads the file, I created another thread fileLoadIndicator to show something like the busy indicator on the screen. What I am trying to do now is: after the fileLoadIndicator thread finishes, I want to enable a button, but only after the fileLoadIndicator thread is finished.

My attempts:

loadFile();// the very heavy file
            /**
             * The below thread "fileLoadIndicator"is to show busy indicator while our main file  
 that takes approx. 8 seconds to be loaded
             * 
             */
            fileLoadIndicator = new Thread(fileLoadIndicatorRun);
            fileLoadIndicator.start();

            indicatorMonitor = new Thread(indicatorMonitorRun);
            indicatorMonitor.start();
 ...
 ...
 Runnable fileLoadIndicatorRun = new Runnable() {

    @Override
    public void run() {
        // TODO Auto-generated method stub
        statusarea.append(Log.w(TAG, "busyIndicatorRunnable", "Loading."));
        StringBuilder sb = new StringBuilder(".");
        do {
            try {
                fileThread.join(1500);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            sb.append(".");
            statusarea.append(sb.toString());
        } while (fileThread.getState() != State.TERMINATED);
        //statusarea.append("/n");
    }
};

Runnable indicatorMonitorRun = new Runnable() {

    @Override
    public void run() {
        // TODO Auto-generated method stub
        try {
            fileLoadIndicator.join();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        setViewEnableState(Bpause, true);
    }
};

But what happens in the indicatorMonitorRun is, the indicatorMonitor thread waits until the whole method loadFile() , which process the heavy file line by line and the whole process might takes 70 minutes, finishes. I just want to enable a button, only when the fileLoadIndicator thread finishes, and I should not wait until the whole file is loaded and processed which a very long time.

Kindly please let me know how can I do so.

I would suggest using ExecutorService to manage your thread pools and if you're using Java 8, take advantage of CompletableFuture as it simplifies these types of tasks without requiring complex thread wait/notify and java.util.concurrency types, for example:

package so.thread.wait;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class LongThreadWait {

  public static void main(String[] args) throws Exception {

    // thread pool for long running loaders
    final ExecutorService fileLoaders = Executors.newCachedThreadPool();

    // hook to be invoked when the file is done loading
    final CompletableFuture<Long> completionFuture = new CompletableFuture<>();
    completionFuture.thenAcceptAsync(LongThreadWait::completionConsumer);

    fileLoaders.submit(new FileLoader(completionFuture));

    Thread.sleep(TimeUnit.SECONDS.toMillis(3));
  }

  private static void completionConsumer(Long millis) {
    System.out.println("Completed on Thread [" + Thread.currentThread().getName() + "] in " + millis + " ms");
  }

  private static class FileLoader implements Runnable {
    private CompletableFuture<Long> completionFuture;

    public FileLoader(CompletableFuture<Long> completionFuture) {
      this.completionFuture = completionFuture;
    }

    @Override
    public void run() {
      long start = System.currentTimeMillis();
      // load file for a long time
      System.out.println("Loading file on Thread [" + Thread.currentThread().getName() + "]");

      try {
        Thread.sleep(TimeUnit.SECONDS.toMillis(2));
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      long end = System.currentTimeMillis();
      // invoke the completion future with the elapsed milliseconds
      completionFuture.complete(end - start);
    }
  }

}

The CompletableFuture.thenAcceptAsync(..) by default runs the supplied hook in the default "ForkJoin" thread pool in the JVM, there is an optional second argument where you can supply your own ExecutorService to define what thread the completion hook is executed on.

This type of setup simplifies thread management and complex wait semantics.

You should also note that CompletableFuture has a comprehensive fluent API to make complex chaining of thread results simpler.

Consider using a CountDownLatch . Initialize this to 1. When your loading thread is done, it can call countDown . Your monitor thread can either poll count or simply await completion.

You could used a "ExecutorService" to create a thread pool, then monitor the threads and wait for the threads to terminate to enable the button.

 class FileThreadThread implements Runnable {
        public FileThreadThread() {

        }

        @Override
        public void run() {

        }       
}


class FileLoadIndicatorRunThread implements Runnable {
    private ExecutorService fileLoadIndicatorExecutor = null;

    @Override
    public void run() {
        if (fileLoadIndicatorExecutor == null || fileLoadIndicatorExecutor.isShutdown()) {
            fileLoadIndicatorExecutor = Executors.newCachedThreadPool(CustomizableThreadFactory.createSingleNamedFactory("FileLoaderThreadPool"));
        }


        for(int i=0; number_of_files; i++){
            fileLoadIndicatorExecutor.execute(new FileThreadThread());
        }
        //Request executor shutdown after all threads are completed
        fileLoadIndicatorExecutor.shutdown();           

        while (isRunning) {
            boolean threadTerminated = fileLoadIndicatorExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
            if(threadTerminated){
                // enable a button

            isRunning =  false;
            }               
        }
    }
}

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