Another good practice to check when our threads have finished without block the thread waiting to recover the Future object from our Callable is to create our own implemetation for Runnables, using it together with the execute()
method.
In the next example, I show a custom class which implements Runnable with a internal callback, with allow us to know when the runnables are finished and use it later in our ThreadPool:
public class CallbackTask implements Runnable {
private final Runnable mTask;
private final RunnableCallback mCallback;
public CallbackTask(Runnable task, RunnableCallback runnableCallback) {
this.mTask = task;
this.mCallback = runnableCallback;
}
public void run() {
long startRunnable = System.currentTimeMillis();
mTask.run();
mCallback.onRunnableComplete(startRunnable);
}
public interface RunnableCallback {
void onRunnableComplete(long runnableStartTime);
}
}
And here is our ThreadExecutor Implementation:
public class ThreadExecutorExample implements ThreadExecutor {
private static String TAG = "ThreadExecutorExample";
public static final int THREADPOOL_SIZE = 4;
private long mSubmittedTasks;
private long mCompletedTasks;
private long mNotCompletedTasks;
private ThreadPoolExecutor mThreadPoolExecutor;
public ThreadExecutorExample() {
Log.i(TAG, "[ThreadExecutorImpl] Initializing ThreadExecutorImpl");
Log.i(TAG, "[ThreadExecutorImpl] current cores: " + Runtime.getRuntime().availableProcessors());
this.mThreadPoolExecutor =
(ThreadPoolExecutor) Executors.newFixedThreadPool(THREADPOOL_SIZE);
}
@Override
public void execute(Runnable runnable) {
try {
if (runnable == null) {
Log.e(TAG, "[execute] Runnable to execute cannot be null");
return;
}
Log.i(TAG, "[execute] Executing new Thread");
this.mThreadPoolExecutor.execute(new CallbackTask(runnable, new CallbackTask.RunnableCallback() {
@Override
public void onRunnableComplete(long RunnableStartTime) {
mSubmittedTasks = mThreadPoolExecutor.getTaskCount();
mCompletedTasks = mThreadPoolExecutor.getCompletedTaskCount();
mNotCompletedTasks = mSubmittedTasks - mCompletedTasks; // approximate
Log.i(TAG, "[execute] [onRunnableComplete] Runnable complete in " + (System.currentTimeMillis() - RunnableStartTime) + "ms");
Log.i(TAG, "[execute] [onRunnableComplete] Current threads working " + mNotCompletedTasks);
}
}));
}
catch (Exception e) {
e.printStackTrace();
Log.e(TAG, "[execute] Error, shutDown the Executor");
this.mThreadPoolExecutor.shutdown();
}
}
}
/**
* Executor thread abstraction created to change the execution context from any thread from out ThreadExecutor.
*/
interface ThreadExecutor extends Executor {
void execute(Runnable runnable);
}
I did this example to check speed of my threads in milliseconds when they are executed, without use Future. You can take this example and add it to your app to control the concurrent task working, and the completed/finished ones. Checking in all moment, the time that you needed to execute that threads.