Java 一个线程如何等待另一个线程完成某些操作

Java 一个线程如何等待另一个线程完成某些操作,java,multithreading,Java,Multithreading,如下面代码所示,我正在工作线程fileThread上加载一个沉重的文件,当该线程加载该文件时,我创建了另一个线程fileLoadIndicator,以在屏幕上显示类似于忙指示器的内容。我现在要做的是:在fileLoadIndicator线程完成之后,我想启用一个按钮,但只有在fileLoadIndicator线程完成之后 我的尝试: loadFile();// the very heavy file /** * The below thread

如下面代码所示,我正在工作线程
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);
    }
};
但是
指示符监视器运行时发生的情况是,
指示符监视器
线程等待整个方法
装入文件()
,该方法逐行处理沉重的文件,整个过程可能需要70分钟。我只想启用一个按钮,只有当
fileLoadIndicator
线程结束时才启用,我不应该等到整个文件加载和处理完成,这需要很长时间


请告诉我如何才能做到这一点。

请考虑使用一种新的方法。将其初始化为1。加载线程完成后,它可以调用。监视器线程可以轮询,也可以简单地完成。

我建议使用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);
    }
  }

}
包so.thread.wait;
导入java.util.concurrent.CompletableFuture;
导入java.util.concurrent.ExecutorService;
导入java.util.concurrent.Executors;
导入java.util.concurrent.TimeUnit;
公共类长线程等待{
公共静态void main(字符串[]args)引发异常{
//用于长时间运行的加载程序的线程池
final ExecutorService fileLoaders=Executors.newCachedThreadPool();
//文件加载完成时要调用的钩子
final CompletableFuture completionFuture=新的CompletableFuture();
completionFuture.TheAcceptionSync(LongThreadWait::completionConsumer);
submit(新文件加载器(completionFuture));
睡眠(时间单位为秒,toMillis(3));
}
专用静态void completionConsumer(长毫秒){
System.out.println(“在”+millis+“ms”中的线程[“+Thread.currentThread().getName()+”]上完成”;
}
私有静态类FileLoader实现可运行{
私人完成未来完成未来;
公共文件加载器(CompletableFuture completionFuture){
this.completionFuture=completionFuture;
}
@凌驾
公开募捐{
长启动=System.currentTimeMillis();
//长时间加载文件
System.out.println(“在线程[“+Thread.currentThread().getName()+”])上加载文件;
试一试{
睡眠(时间单位为秒,时间单位为2);
}捕捉(中断异常e){
e、 printStackTrace();
}
long end=System.currentTimeMillis();
//使用经过的毫秒数调用未来完成
completionFuture.complete(结束-开始);
}
}
}
CompletableFuture.TheAcceptySync(..)默认情况下在JVM的默认“ForkJoin”线程池中运行提供的钩子,有一个可选的第二个参数,您可以在其中提供自己的ExecutorService来定义在哪个线程上执行完成钩子

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

您还应该注意,CompletableFuture有一个全面的fluent API,可以简化线程结果的复杂链接。

您可以使用“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;
            }               
        }
    }
}

使用单独的runnable…?@MattBall我使用的是一个runnable吗?在我的代码中,我使用了两个runnable。到什么程度可以将我的线程分隔为两个以上的可运行程序?如果我遗漏了一些内容,很抱歉-但是您不想在另一个线程下运行“loadfile()”吗。。。?我正在阅读您提供的货源的订单。这将停止主应用程序的大延迟。注意:确保子线程上存在超时,否则执行器将永远不会终止。