C Threads and HTTP Requests
This appendix introduces concepts in concurrency and threading, which are used extensively by Android though a framework-specific classes and options. For clarity, these concepts are introduced though a set of practice exercises in straight Java (though similar code can be utilized in Android).
The code for these exercises can be found at https://github.com/info448-s17/lab-threads-http.
Additionally, this appendix introduces the Java code used to send network requests. Android will use exactly this code, but in order to experiment with it separate from the Android framework you’ll be making network connections directly from Java.
C.1 Concurrency
Concurrency the process by which we have multiple processes (think: methods) running at the same time. This can be contrasted with processes that run serially, or one after another.
C.1.1 An Example: Algorithm Races!
As an example, note that one of the main concerns of computer science and software in general is speed: how fast will a particular program or algorithm run? For example, give two of the many sorting algorithms that have been invented, which one can sort a list of numbers more quickly?
- Sorting algorithms are usually covered in UW’s CSE 373 course, but don’t worry if you haven’t taken that course yet! All you need to know is that there are different techniques for sorting numbers, these techniques are given funny names, and one technique may be faster than another
Consider the provided SortRacer.java
class (found in the src/main/java
folder). The main
method for this program runs two different sorting algorithms (currently Merge Sort and Quicksort), reporting when each one is finished.
Practice: Run this program using gradle: ./gradlew -q runSorts
. Note that it may take a few seconds for it to build and begin running, and the sorting itself may take a few seconds!
Of course, it’s not really a “race” at the moment: rather, each sorting algorithm is run serially (that is, one after another). If we really wanted them to race, we’d like the algorithms to run concurrently (at the same time).
Computers as a general rule do exactly one thing a time: your central processing unit (CPU) just adds two number together over and over again, billions of times a second
- The standard measure for rate (how many times per second) is the
hertz
(Hz). So a 2 gigahertz (GHz) processor can do 2 billion operations per second.
However, we don’t realize that computers do only one thing at a time! This is because computers are really good at multitasking: they will do a tiny bit of one task, and then jump over to another task and do a little of that, and then jump over to another task and do a little of that, and then back to the first task, and so on.
These “tasks” are divided up into two types: processes and threads. Read this brief summary of the difference between them.
So by breaking up a program into threads (which are “interwoven”), we can in effect cause the computer to do two tasks at once. This is especially useful if one of the “tasks” might take a really long time–rather than blocking the application, we can let other tasks also make some progress while we’re waiting for the long task to finish.
C.1.2 Threading the Race
Currently the two sorting algorithms run in the same thread, one after another. You should break them into two different threads that can run concurrently, letting them actually be able to race!
In Java, we create a Thread by creating a class that implements
the Runnable
interface. This represents a class that can be “run” in a separate thread! The run()
method required by the interface acts a bit like the “main” method for that Thread: when we start the Thread running, that is the method that will get called.
Practice: Create two new Runnable
classes, one for each Sorting method.
These should be nested classes (think: should they be
static
?).When each
Runnable
isrun
, you should create a new shuffled array of numbers and then call the appropriate sorting method on that list. Remember to print out when you start and finish sorting (just like is currently done in themain()
method).
If we just instantiate the Runnable()
and call its run()
method, that won’t actually execute the method on a different thread (remember: an interface is just a “sign”; we could have called the interface and method whatever we wanted and it would still compile). Instead, we execute code on a separate thread by using an instance of the Thread
class. This class actually does the work of running code on a separate thread.
Thread
has a constructor that takes in a Runnable
instance as a parameter—you pass an object representing the “code to run” to the Thread
object (this is an example of the Strategy Pattern). You then can actually start the Thread
by calling its .start()
method (not the run
method!).
Practice: Modify the main()
method so you create new Threads
to execute each Runnable
Make sure you actually start()
the threads!
- Anonymous variables will be useful here; you don’t need to assign a variable name to the
Runnable
objects or even theThread
objects if you just use them directly.
Now run your program! Do you see the Threads running at the same time? Try running the program multiple times and see what kind of differences you get.
There are some print statements you can uncomment in the
Sorting
class if you want to see more concrete evidence of the Threads running concurrently.You are also welcome to try racing different sorting algorithms (you’ll want to use a smaller list of numbers, particularly for the painfully slow BubbleSort). You can even race more than two algorithms—just create additional Threads!
And that’s the basics of creating Threads in Java!
C.2 HTTP Requests
Consider the provided MovieDownloader.java
class (found in the src/main/java/
folder). This Java code (which is directly portable to Android) accesses the database at omdbapi.com, a wrapper around the IMDB API calls for getting information about movies.
You can run this program with the ./gradlew -q runMovies
task. It will prompt you for a movies to search for, and then print out the results (in JSON format).
Practice: add descriptive comments to the downloadMovieData()
method, explaining what the code does and how it works. The goal is to understand the classes and methods are that are being used here (particularly the use of HttpUrlConnection
, InputStream
, and BufferedReader
), and demonstrate that understanding through explanatory comments. You should also pay particular attention to the use of try/catch
blocks (see here for one explanation).
Note that we’ll utilize this exact code in Android, so you should be familiar with what it is doing!