一个线程如何等待,直到另一个线程完成触发某些操作

时间:2015-01-02 15:04:52

标签: java multithreading

如下面的代码所示,我在工作线程fileThread上加载了一个繁重的文件,当该线程加载文件时,我创建了另一个线程fileLoadIndicator以显示繁忙的指示符屏幕上。我现在要做的是:在fileLoadIndicator线程完成后,我想启用一个按钮,但只有在fileLoadIndicator线程完成后才能启用。

我的尝试:

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

indicatorMonitorRun中发生的情况是,indicatorMonitor线程等待整个方法loadFile(),它逐行处理繁重的文件,整个过程可能需要70分钟,饰面。我只想在fileLoadIndicator线程完成时启用一个按钮,我不应该等到整个文件加载并处理了很长时间。

请告诉我如何才能这样做。

3 个答案:

答案 0 :(得分:3)

我建议使用ExecutorService来管理你的线程池,如果你正在使用Java 8,可以利用CompletableFuture,因为它简化了这些类型的任务,而不需要复杂的线程等待/通知和java.util.concurrency类型,例如:

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

}

默认情况下,CompletableFuture.thenAcceptAsync(..)在默认情况下运行提供的挂钩&#34; ForkJoin&#34;在JVM中的线程池中,有一个可选的第二个参数,您可以在其中提供自己的ExecutorService来定义执行完成挂钩的线程。

这种类型的设置简化了线程管理和复杂的等待语义。

您还应注意,CompletableFuture具有全面的流畅API,可以简化线程结果的复杂链接。

答案 1 :(得分:0)

考虑使用CountDownLatch。将其初始化为1.加载线程完成后,可以调用countDown。您的监控线程可以轮询count或仅await完成。

答案 2 :(得分:0)

您可以使用“ExecutorService”创建线程池,然后监视线程并等待线程终止以启用该按钮。

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