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.