Introduction to Multithreading Tutorial

Every time you invoke a class containing the main() method you are running your compiled bytecode on a single thread called the main thread. When it comes to threads, the main thread is super important. Java gives us the ability to create and spawn child threads from the main thread. Why on earth would we want to create additional threads? The answer to that question is only learned through experience ... the kind of experience that makes your program appear to be hung up in an endless loop! Let me give you a couple of examples.

Let's imagine that we have a program that downloads large images from a website to the local drive. Depending upon the connection speed, it may take 10 seconds, or it may take 10 minutes. Either way we need to interact with the user to let them know that our program is downloading a file and not just hung up in la-la-land. If we put our code to download each image into a method that is invoked on the main thread, we would have no way to interact with the user while each statement in our method is executing. We can accomplish our goal by creating a class that will run on a new thread and then invoke an instance of that class from the code running on the main thread. The main thread can then provide your user with regular updates on the download progress at set intervals - like every 1/2 second or so. Of course I will show you exactly how to do just that, only in a future tutorial.

As another example, let's imagine that we have a program that is trying to determine if a bunch of very large numbers (100's of digits long) are prime. If we invoke a custom method on the main thread to begin calculations, then we could only calculate one number at a time, not to mention our program might appear to be hung while it is calculating away. In addition to that issue, you might be underutilizing your computer if it contains a multi-core-multi-thread processor. Imagine if the main thread could launch 10 child threads with each one working to determine if another large number is prime - you would speed up your goal by 1000% and you will still be able to interact freely on the main thread - bonus!

At the top of the thread hierarchy is a class named Thread and an interface named Runnable. Every thread has a life cycle. The life cycle of a thread is well defined into a total of six states:

  • NEW - A thread has been declared, but has not yet started is in this state.
  • RUNNABLE - In this state a thread is executing in the JVM.
  • BLOCKED - In this state a thread is blocked waiting for a monitor lock or intrinsic lock. I'll explain in later down the road.
  • WAITING - A thread that is waiting indefinitely for another thread to perform a particular action is in this state.
  • TIMED WAITING - A thread that is waiting for another thread to perform an action for up to a specified waiting time is in this state.
  • TERMINATED - A thread that has exited is in this state.
Let's get started by toying around with some of the methods and properties of the main thread.



Open the command prompt (CMD - see the Getting Started ) and type in the following commands.

C:\Windows\System32>cd \
C:\>md Java
C:\>cd Java
C:\Java>
C:\Java>md MultithreadingIntro
C:\Java>cd MultithreadingIntro
C:\Java\MultithreadingIntro>Notepad MultithreadingIntro.java

Copy and Paste, or type the following code into Notepad and be sure to save the file when you are done.


class MultithreadingIntro {
    public static void main(String args[]) {
        Thread mt = Thread.currentThread();
        System.out.println("Main thread name = " + mt.getName());
        System.out.println("Main thread state = " + mt.getState());
        System.out.println("Thread class MAX_PRIORITY = " + Thread.MAX_PRIORITY);
        System.out.println("Thread class MIN_PRIORITY = " +Thread.MIN_PRIORITY);
        System.out.println("Thread class NORM_PRIORITY = " +Thread.NORM_PRIORITY);
        System.out.println("Main thread priority = " + mt.getPriority());
        System.out.println("Main thread group = " + mt.getThreadGroup());
        System.out.println("Have the main thread sleep for 1 second eight times...");
        for (int i = 0; i < 8; i++) {
            System.out.println("Sleeping ... " + (i+1));	
            try {
                mt.sleep(1000);
            } catch (InterruptedException e) {
                System.out.println("main thread interupted: " + e.getMessage());
            }
        }
        System.out.println("Main thread toString() = " + mt.toString());
    }
}

Now switch back to the command prompt (CMD) and type in javac MultithreadingIntro.java and press Enter.
Now type in java MultithreadingIntro and press Enter.


C:\Java\MultithreadingIntro>javac MultithreadingIntro.java
C:\Java\MultithreadingIntro>java MultithreadingIntro
Main thread name = main
Main thread state = RUNNABLE
Thread class MAX_PRIORITY = 10
Thread class MIN_PRIORITY = 1
Thread class NORM_PRIORITY = 5
Main thread priority = 5
Main thread group = java.lang.ThreadGroup(name=main,maxpri=10)
Have the main thread sleep for 1 second eight times...
"Sleeping ... 1
"Sleeping ... 2
"Sleeping ... 3
"Sleeping ... 4
"Sleeping ... 5
"Sleeping ... 6
"Sleeping ... 7
"Sleeping ... 8
Main thread toString() = Thread[main,5,main]


Final thoughts

Multithreading is a complex topic and it is one of the most important things to have a clear understanding of. I will be dedicating some time to a whole bunch of tutorials on this topic.


Tutorials