How to speed up applications using threads in java

Today we are going to show how to speed up applications using threads in java. We use divide and conquer algorithm to check if program execution can be divided into fragments that can be executed separately.
Our sample program is a simple downloader application which downloads images available under URLs. Program iterates through urls and downloads images one by one. To speed up our program we download an image in a separate thread.
In this tutorial you will find:
- How to read bytes from URL to file
- How to download files in a single thread
- Hot to download files in multiple threads
- Execution time comparison


How to read bytes from URL to file


To download files from URL to a local file you need to simply connect to a given URL address, read bytes and at the same time write them to a file. We have a class that implements this functionality.

ImageDownloader.java

package com.itcuties.samples;

import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;

/**
 * Download image files.
 *
 * @author itcuties
 *
 */
public class ImageDownloader {
	// Image path
	private String imageUrl;
	// Destionation local file
	private String destinationPath;

	public ImageDownloader(String imageUrl, String destinationPath) {
		this.imageUrl = imageUrl;
		this.destinationPath = destinationPath;
	}

	/**
	 * Download image to local drive
	 * @throws Exception
	 */
	public void download() throws Exception {
		// Open connetction to the image
		URL url = new URL(imageUrl);
		InputStream is = url.openStream();
		// Stream to the destionation file
		FileOutputStream fos = new FileOutputStream(destinationPath);

		// Read bytes from URL to the local file
		byte[] buffer = new byte[4096];
		int bytesRead = 0;
		while ((bytesRead = is.read(buffer)) != -1)
			fos.write(buffer,0,bytesRead);

		// Close destination stream
		fos.close();
		// Close URL stream
		is.close();
	}
}


How to download files in a single thread


Our code iterates through the URLs and for each one we create ImageDownloader object and call download method.

		...
		// Images URLs
		String[] imagesToDownload = new String[] {
				"http://fbapp.itcuties.com/middle/_DSC4598.jpg",
				"http://fbapp.itcuties.com/middle/_DSC4516.jpg",
				"http://fbapp.itcuties.com/middle/_DSC4796.jpg",
				"http://fbapp.itcuties.com/middle/_DSC4776.jpg",
				"http://fbapp.itcuties.com/middle/_DSC4505.jpg",
				"http://fbapp.itcuties.com/middle/_DSC4448.jpg",
				"http://fbapp.itcuties.com/middle/_DSC4590.jpg",
				"http://fbapp.itcuties.com/middle/_DSC4514.jpg",
				"http://fbapp.itcuties.com/middle/_DSC4698.jpg",
				"http://fbapp.itcuties.com/middle/_DSC4434.jpg"
		};

		String destinationFolder = "D:\\Workspace\\ITC\\tmp\\";
		...
			int nameIndex 	= 0;
			long startTime 	= 0;
			long endTime 	= 0;

			// Download images in this thread
			System.out.println("Downloading "+imagesToDownload.length+" images with single thread");
			startTime = System.currentTimeMillis();
			for (String url: imagesToDownload) {
				new ImageDownloader(url,destinationFolder + "single" + (nameIndex++) + ".jpg").download();
			}
			endTime = System.currentTimeMillis();
			System.out.println("\tdownload time: " + (endTime-startTime)+" ms");

			...


Hot to download files in multiple threads


The key modification of our program is calling a download method of ImageDownloader object for each of the URLs in a separate thread. Our program needs to wait for all the threads to finish downloading operation. We will use Object.wait() and Object.notify() methods to synchronize main threads and downloading threads.
We need a lock object to synchronize execution on. Each thread will register it’s execution in that lock object and after finishing will unregister itself.

Lock.java

package com.itcuties.samples;

public class Lock {

	private int runningThreadsNumber;

	public Lock() {
		runningThreadsNumber = 0;
	}

	public int getRunningThreadsNumber() {
		return runningThreadsNumber;
	}

	public void addRunningThread() {
		runningThreadsNumber++;
	}

	public void removeRunningThread() {
		runningThreadsNumber--;
	}
}

Downloading will take place in a separate thread. We need a class that is going to implement this behavior.

DownloadThread.java

package com.itcuties.samples;

public class DownloadThread extends Thread {
	private String imageUrl;
	private String destinationPath;
	private Lock lock;

	public DownloadThread(String imageUrl, String destinationPath, Lock lock) {
		this.imageUrl = imageUrl;
		this.destinationPath = destinationPath;
		this.lock = lock;
	}

	@Override
	public void run() {
		try {
			lock.addRunningThread();

			new ImageDownloader(imageUrl, destinationPath).download();

			lock.removeRunningThread();

			synchronized (lock) {
				lock.notify();
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

At the beggining of the execution our class registers itself in the lock object. Then the download task i started and when it’s finished our thread unregisters itself from the lock object. At the end our thread notifies a thread that is waiting on the lock about the fact that the download is complete.
Our download code now looks like this

		...
		// Images URLs
		String[] imagesToDownload = new String[] {
				"http://fbapp.itcuties.com/middle/_DSC4598.jpg",
				"http://fbapp.itcuties.com/middle/_DSC4516.jpg",
				"http://fbapp.itcuties.com/middle/_DSC4796.jpg",
				"http://fbapp.itcuties.com/middle/_DSC4776.jpg",
				"http://fbapp.itcuties.com/middle/_DSC4505.jpg",
				"http://fbapp.itcuties.com/middle/_DSC4448.jpg",
				"http://fbapp.itcuties.com/middle/_DSC4590.jpg",
				"http://fbapp.itcuties.com/middle/_DSC4514.jpg",
				"http://fbapp.itcuties.com/middle/_DSC4698.jpg",
				"http://fbapp.itcuties.com/middle/_DSC4434.jpg"
		};

		String destinationFolder = "D:\\Workspace\\ITC\\tmp\\";
		...
			int nameIndex 	= 0;
			long startTime 	= 0;
			long endTime 	= 0;

			Lock lock = new Lock();	// A lock object to synchronize threads on it.
			System.out.println("Downloading "+imagesToDownload.length+" images with multiple threads");
			startTime = System.currentTimeMillis();
			for (String url: imagesToDownload) {
				DownloadThread dt = new DownloadThread(url, destinationFolder + "multiple" + (nameIndex++) + ".jpg", lock);
				dt.start();	// Start download in another thread
			}

			// Wait here for all the threads to end
			while (lock.getRunningThreadsNumber() > 0)
				synchronized (lock) {
					lock.wait();
				}

			endTime = System.currentTimeMillis();
			System.out.println("\tdownload time: " + (endTime-startTime)+" ms");
			...

We start a new thread for each downloaded URLs. After starting threads we need to wait for them to finish execution.


Execution time comparison


Does it really work? Our tests show that program was executed faster when using threads rather than a single thread.
java multithread program execution comparison

Find out for yourself if it really works. Download our code here.

2 Responses to "How to speed up applications using threads in java"

  1. Steve says:

    Very nice article – thank you!

    Reply
  2. srinivasan says:

    Ii is a nice article – Thank you very much

    Reply

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>