Java Async Future

That is going to be my first post and today I will explain purpose of Java Future

The main purpose of Java Future is expecting returning value from paralel task in the future. For example if you execute new Thread you would be able to do some task in background however it is going to be difficult to return value from that thread once calculations were finished, we will have to use some kind of synchronized middle object as a storage.

Java Future is nearly the same Thread but with possibility to return value in the future. To demonstrate it we will implement simple task:

Task Description:

Download 4k (4096×2160 – 9.1Mb size) wallpaper image from URL (my DropBox) as parallel task, were executed worker would return String of the total KB were downloaded when task will be fully complete.

Implementation:

Lets start from the main class:

package implementation;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class AsyncMain {
	
	public static void main(String[] args)
	{
		new AsyncMain().startRoutine();
	}
	
	private void startRoutine()
	{
		//creating thread pool of single thread (but could be pool of many threads, I just don't need it for this demonstration)
		ExecutorService executor = Executors.newSingleThreadExecutor();
		//creating callable object which expected to return value of String type
		Callable<String> imageDownloader = new AsyncWorker();
		//Executing asynchronous thread which should return value in the future 
		Future<String> asyncThread = executor.submit(imageDownloader);
					
		//Waiting until async thread finish its job
		while (!asyncThread.isDone()) {
			
			try
			{
				//writing to the console once per sec
				System.out.println("Main: Worker still Downloading file...");
				Thread.sleep(1000);
				
			}
			catch(Exception e)
			{
				System.out.println("Main thread was interupted");
			}
		}
				

		String result = "";
		try {
			//getting return value from async thread
			result = asyncThread.get();
			//printing returned value from async thread to console
			System.out.println("Main: [Returned result from AsyncThread is: "+result+"]");
		} catch (Exception e) {
			e.printStackTrace();
		} 
			

		
		//Telling to pool executor to shutdown once it thread is finished
		executor.shutdown();
		
	}

	
}


As you can see, we create thread pool, define future callable and execute it.
Future has nice method isDone() which allow to check if parallel task was complete before trying to get value. However if you will try to get value without check isDone() it will blocked the thread until data will be available

Now lets look at the Worker or slave if you prefer:

package implementation;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.concurrent.Callable;



public class AsyncWorker implements Callable<String>{

	@Override
	public String call() throws Exception {
		
		//variables used during the progress
        String result = null;
        int totalBytes = 0;
        int size;
        int sizeKb;
        float onePrcnt;
        byte data[] = new byte[1024];
        int count;
        float prevProcent = 0;
        
        //in / out streams
        BufferedInputStream in = null;
        FileOutputStream fout = null;
        
        //URLs to download: from / to
        String urlLink ="https://dl.dropboxusercontent.com/u/15715229/palousecanola.jpg";
        String outputPath = "C:/AsyncTest";
        String filename = "Palousecanola.jpg";

		try
        {
			//Create new url object
			URL url = new URL(urlLink);
			//opening connection
			URLConnection con = url.openConnection();
			//setting size of remote content
			size = con.getContentLength();
			sizeKb = size / 1024;
			onePrcnt = size / 100;
			//Closing connection ??? there should be more delicate way how to get size of downloadable content instead of opening and closing connection
			//but stream type of connection doesn't allow to get the size of entire stream, however download process is faster
			//Anyway we need size just to nicely represent amount of downloaded in percentage 
			con = null;
			
			//Preparing input stream
            in = new BufferedInputStream(url.openStream());
            
            //prepare output file location;
            new File(outputPath).mkdirs();
            //Preparing output file stream
            fout = new FileOutputStream(outputPath+"/"+filename);
            //downloading file
            while ((count = in.read(data, 0, 1024)) != -1)
            {
            	//Calculating total of bytes downloaded
            	totalBytes += count;
            	//writing to the file new bytes
                fout.write(data, 0, count);
                //display console message once per one full percent or more then one
                if(totalBytes >= onePrcnt)
                {
                	//calculation in percentage how much in total was downloaded
                	float totalPrcnt = totalBytes / onePrcnt;
                	//checking if total minus previous total would be more then 1%
                	if(totalPrcnt - prevProcent > 1)
                	{
                		prevProcent = totalPrcnt;
                		//Then display message
                		System.out.println("AsyncWorker: [Downloaded: "+(int)totalPrcnt+"% or "+totalBytes / 1024+"Kb from: "+sizeKb+"]");
                	}
                }
                	
            }
            
            //Setting return statement
            result = "Download of total "+totalBytes / 1024+"KB was complete";
        }
		catch(Exception e)
		{
			//setting return statement to contain exception message 
			result = "Application was Scrashed because of: "+e;
		}
        finally
        {
        	//closing [in] and [out] streams regardless was there exception or not
            if (in != null)
                in.close();
            if (fout != null)
                fout.close();
        }
		//internal message of complete state
		System.out.println("AsyncWorker: [Download Complete!]");
		//returning value
		return result;
	}

}

Our worker just connects to web (my drop box file) and try to download it.
I had to make connection to the web twice just to get file size for nice representation of download progress in percentage, however downloading file through the input stream does not allow you to query content weight but is much faster (you can test it your self), so I had to open connection get file size, close connection and open stream connection again.

Returned String is a result of downloaded file size or crash report, in both ways async task return value of String type to main thread.

This project source can be downloaded from my:

One response to “Java Async Future

Leave a comment