Simple Threads – a bit more complex approach

It’s great to relax and spend time with family. To much relaxing might get boring after a while so it’s time start creating!

Before moving on with our journey, I wanted to evolve a bit more the SimpleThreadsAPI. And so I did. But I also got irresolute about where is best to place some APIs. Should I keep the basic InterruptibleRunnable interface as it is? Or shall I add some more APIs to it, which frankly, are useful?

If you haven’t read the previous article, now it’s a good time to get into the basics of Java Threads: Cancel or Pause a Thread’s execution – the basics.

There is a well defined difference as time and space is concerned between the real state of the process and the state imposed by the user. A user call to pause() the process, but the process doesn’t pause immediately. Firstly, it’s on another thread, secondly the checkInterruption() will actually pause it. So far I’ve decided to keep 2 fields, one for the state the user set, called “state”, the other for the actual state of the process called “realState”. This can be done with one field as well, but expanding the range of states the process can have.

The next issue is that I’ve added property change notifications. This is great as the user can always know when the state of the process changed, or really changed. And it also allows using other properties in subclasses. But shall I add the public methods dealing property changes in the interface, or leave them in the default abstract implementation. Obvious, they should be in the interface, but I don’t really like to make that crowded. I love it simple, but might not be enough.

In order to provide a bit more complex example then the movement of a progress bar back and forth, I did a bit of refactoring on the test class. It’s much more simple now, and I could easily extend it.

I’ve implemented another process which downloads a file from a specified url location and store it on your machine in a specified file. I used this process in the second test sample. The location of the download process is here: https://github.com/bogdanudrescu/SimpleThreadsAPI/blob/master/src/grape/simple/threads/test/DownloadProcess.java

Let’s take look at and discuss the code, thanks to our friend, archerimagine, who suggested this.

Our DownloadProcess extends from AbstractInterruptibleRunnable, which is the default implementation of the InterruptibleRunnable. Instead of run(), AbstractInterruptibleRunnable requires one abstract method to be implemented, the execute() method. So here we go:

	protected void execute() throws Exception {

Then, in this particular case – downloading a file – we need to open a url connection. As you can see, the connection object is an instance member. You’ll see soon why.

		URL url = new URL(urlToDownload);

		connection = url.openConnection();

		System.out.println("Connecting to " + urlToDownload);

		// Read the lenght of the download content.
		String contentLengthString = connection.getHeaderField("Content-Length");

		checkInterruption(); // THIS IS THE TRICK

		long contentLength = Long.parseLong(contentLengthString);

		System.out.println("Connection established!");

After obtaining the connection, we need to see how large is our file, so we read the Content-Length parameter from the header of the http response. Now, this will actually download data from the server, and we don’t know how much time will take for the server to respond. What if at this moment the user cancel the process? We’re still waiting in getHeaderField("Content-Length") call and the process won’t cancel. The solution is to override the cancel() method and to set the timeout on the connection to the minimum value – 1 mills, which will force the connection to timeout.

	public synchronized void cancel() {
		super.cancel();

		// THIS IS THE OTHER TRICK
		connection.setConnectTimeout(1);
		connection.setReadTimeout(1);
	}

Then, in case of a timeout, getHeaderField("Content-Length") will end its execution with null, and the next call is checkInterruption(). As I said, this is the trick to pause or cancel your process. It will check on the state of the process and will throw an exception to cancel it or will call wait() to pause it. In your process make regular calls to this method, leaving as less time as possible in-between calls.

Let’s move on with our download. We need now to read the input stream and to store the bytes in an output stream pointing to our file. I choose 4kb as an intermediate buffer, and I’m writing the bytes immediately in the output stream. In most of the cases this should be enough.
Then I’m doing something cool. I said that I’ve added property listeners. I’ve implemented one to track the completion percent of the process. Just calling setPercentCompleted(float percent) will fire a property change event. Of-course, you need to call that because I don’t know what are the steps of your process 😉
And at the end of each loop I’m checking again if the process should cancel or pause. Just call checkInterruption(). It’s that simple.

		// Gets the data from the input stream and puts it into the output stream.
		inputStream = connection.getInputStream();
		outputStream = new FileOutputStream(fileNameToStore);

		byte[] bytes = new byte[4096];
		int length = -1;
		long contentLengthRead = 0;

		while ((length = inputStream.read(bytes)) != -1) {

			outputStream.write(bytes, 0, length);
			outputStream.flush();

			contentLengthRead += length;

			// Set the completed percent.
			setPercentCompleted(100f * contentLengthRead / contentLength);

			checkInterruption(); // THIS IS THE TRICK
		}

There is also a method called when the process ends, no matter if it’s canceled or it terminates normally. You can override it to close connections or any other finalizers you might need to do. But all the code here needs to be fast. In our case I have to make sure the input and output streams get closed.
Make sure that no exception will leave this method. The execute() method comes with throws Exception, but this one is intentionally left without to force you to catch any problems, and to make sure you close everything correctly.

	protected void executed() {

		System.out.println("Download finished.");

		if (outputStream != null) {
			try {
				outputStream.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}

		if (inputStream != null) {
			try {
				inputStream.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

And now, this is how the process is created. We also register for the “percentCompleted” change, in order to move the progress on the progress bar.

	protected InterruptibleRunnable createProcess() {
		InterruptibleRunnable process = new DownloadProcess(urlTextField.getText(), fileTextField.getText());
		process.addPropertyChangeListener("percentCompleted", new PercentCompletedListener());
		return process;
	}

And when the play button gets hit, we only start our process on a Thread and we also register to the “realState” change to enable/disable the play/pause/stop buttons accordingly:

		process = createProcess();
		process.addPropertyChangeListener("realState", new RealStatePropertyListener());

		new Thread(process).start();

In order to pause the process I just call:

		process.pause();

And to stop it:

		process.cancel();

It’s that simple 😉

This is how the test app looks, and the code is here: https://github.com/bogdanudrescu/SimpleThreadsAPI/blob/master/src/grape/simple/threads/test/TestInterruptionDownload.java

Demo

Wish you all a happy life with lot of love!

Threads