The Java Thread class and threading API: getting started

As mentioned in our introduction to threads and threading, the most basic way of programming with threads in Java is to use the java.lang.Thread class. This generally gives the programmer the lowest-level degree of control over threads. (It also means that the Thread API is rarely used in isolation in complex multithreaded Java applications.)

To see how to use Thread in Java, let's dive straight in and see some code. We're going to write a program that "splits itself" into two simultaneous tasks. One task is to print Hello, world! every second. The other task is to print Goodbye, cruel world! every two seconds. OK, it's a silly example.

For them to run simultaneously, each of these two tasks will run in a separate thread. To define a "task", we create an instance of Runnable. Then we will wrap each of these Runnables around a Thread object.

Runnable

A Runnable object defines an actual task that is to be executed. It doesn't define how it is to be executed (serial, two at a time, three at a time etc), but just what. We can define a Runnable as follows:

Runnable r = new Runnable() {
  public void run() {
    ... code to be executed ...
  }
};

Runnable is actually an interface, with the single run() method that we must provide. In our case, we want the Runnable.run() methods of our two tasks to print a message periodically. So here is what the code could look like:

Runnable r1 = new Runnable() {
  public void run() {
    try {
      while (true) {
        System.out.println("Hello, world!");
        Thread.sleep(1000L);
      }
    } catch (InterruptedException iex) {}
  }
};
Runnable r2 = new Runnable() {
  public void run() {
    try {
      while (true) {
        System.out.println("Goodbye, " +
		"cruel world!");
        Thread.sleep(2000L);
      }
    } catch (InterruptedException iex) {}
  }
};

For now, we'll gloss over a couple of issues, such as how the task ever stops. As you've probably gathered, the Thread.sleep() method essentially "pauses" for the given number of milliseconds, but could get "interrupted", hence the need to catch InterruptedException. We'll come back to this in more detail in the section on Thread interruption and InterruptedException. The most important point for now is that with the Runnable() interface, we're just defining what the two tasks are. We haven't actually set them running yet. And that's where the Thread class comes in...

Thread

A Java Thread object wraps around an actual thread of execution. It effectively defines how the task is to be executed— namely, at the same time as other threads2. To run the above two tasks simultaneously, we create a Thread object for each Runnable, then call the start() method on each Thread:

Thread thr1 = new Thread(r1);
Thread thr2 = new Thread(r2);
thr1.start();
thr2.start();

When we call start(), a new thread is spawned, which will begin executing the task that was assigned to the Thread object at some time in the near future. Meanwhile, control returns to the caller of start(), and we can start the second thread. Once that starts, we'll actually have at least three threads now running in parallel: the two we've just started, plus the "main" thread from which we created and started the two others. (In reality, the JVM will tend to have a few extra threads running for "housekeeping" tasks such as garbage collection, although they're essentially outside of our program's control.)

Next: threading topics

On the next page, we look at the following Java threading topics:


1. A process is essentially a "heavy" unit of multitasking: as an approximation, think of it as an "application" (though it can include 'background' or 'system' processes such a your battery monitor or file indexer). A thread, on the other hand, is a more "lightweight" unit. Different processes generally have certain resources allocated independently of one another (such as address space, file handle allocations), whereas a threads generally share the resources of their parent process.
2. We'll see later that the Thread object also encapsulates other details, such as a thread's priority.


If you enjoy this Java programming article, please share with friends and colleagues. Follow the author on Twitter for the latest news and rants.

Editorial page content written by Neil Coffey. Copyright © Javamex UK 2021. All rights reserved.