Multithreading
What is Java Multithreading?
In Java, a Thread is essentially the Object that represents one piece of work. When you start your application and it starts to run, Java has “spawned” (created) a Thread and this Thread is what will carry out the work that your application is meant to do. What’s interesting to note, is that one Thread can only do one particular task at a time. So that would mean it’s a bit of a bottleneck if your entire application just works off of one Thread right? Right!
Java multithreading allows you to do multiple tasks at the same time. This is possible because modern day computers have multiple CPUs (CPUs are the brain of your computer, and it has a bunch!). One CPU can work on one Thread at a time (unless your CPUs have hyper-threading, in which case it can handle two at a time). So this means that if your computer has 4 CPUs with hyper-threading technologies, your code could potentially handle 8 Threads at the same time. Neat!
The implications of this are that you can take your code and make it perform MUCH better by introducing the use of multithreading. That is of course, if your program would benefit from the use of multithreading, some applications are fairly simple and things would just get over-complicated by adding in Thread logic.
How do we use it in Java?
Well, it’s really not too tough to implement the use of Threads in Java. The trick is ensuring that all the Threads cooperate properly with each other… but I’ll get into that after I show you an example of how to set yourself up with Threads.
All you need to do to use Threads is to have an Object implement the Runnable interface and override the run method. Here’s an example of a Class named Worker.
public class Worker implements Runnable
{
public static void main (String[] args)
{
System.out.println("This is currently running on the main thread, " +
"the id is: " + Thread.currentThread().getId());
Worker worker = new Worker();
Thread thread = new Thread(worker);
thread.start();
}
@Override
public void run()
{
System.out.println("This is currently running on a separate thread, " +
"the id is: " + Thread.currentThread().getId());
}
}
When this code is run, here’s the output I get on my computer:
This is currently running on the main thread, the id is: 1
This is currently running on a separate thread, the id is: 9
So you can see here that there are two different Threads running here. Now in this example, there’s really no need to be using two different Threads because the flow of this code is linear. The trick here would be to introduce the need for multiple Workers to be running at the same time, and to have a lot of work for these Workers to carry out. We can easily create lots of Workers, I’ll just use a for loop to create a handful. But how could we simulate lots of work? Well, we could use the Thread.sleep()
method; this method pauses the thread for a custom defined period of time. When we pause a Thread, this would simulate that Thread being busy doing some sort of actual work! Sweet, so let’s see what that would look like:
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class Worker implements Runnable
{
public boolean running = false;
public Worker ()
{
Thread thread = new Thread(this);
thread.start();
}
public static void main (String[] args) throws InterruptedException
{
List<Worker> workers = new ArrayList<Worker>();
System.out.println("This is currently running on the main thread, " +
"the id is: " + Thread.currentThread().getId());
Date start = new Date();
// start 5 workers
for (int i=0; i<5; i++)
{
workers.add(new Worker());
}
// We must force the main thread to wait for all the workers
// to finish their work before we check to see how long it
// took to complete
for (Worker worker : workers)
{
while (worker.running)
{
Thread.sleep(100);
}
}
Date end = new Date();
long difference = end.getTime() - start.getTime();
System.out.println ("This whole process took: " + difference/1000 + " seconds.");
}
@Override
public void run()
{
this.running = true;
System.out.println("This is currently running on a separate thread, " +
"the id is: " + Thread.currentThread().getId());
try
{
// this will pause this spawned thread for 5 seconds
// (5000 is the number of milliseconds to pause)
// Also, the Thread.sleep() method throws an InterruptedException
// so we must "handle" this possible exception, that's why I've
// wrapped the sleep() method with a try/catch block
Thread.sleep(5000);
}
catch (InterruptedException e)
{
// As user Bernd points out in the comments section below, you should
// never swallow an InterruptedException.
Thread.currentThread().interrupt();
}
this.running = false;
}
}
So what's the output of the code above? Here's what it says on my computer:
This is currently running on the main thread, the id is: 1
This is currently running on a separate thread, the id is: 9
This is currently running on a separate thread, the id is: 10
This is currently running on a separate thread, the id is: 11
This is currently running on a separate thread, the id is: 12
This is currently running on a separate thread, the id is: 13
This whole process took: 5 seconds.
Cool, so that's what I would expect to see. If you look at the code, each worker "sleeps" for 5 seconds, this simulates 5 seconds of work that they are doing. So since we are using multithreading, firing up 5 different workers to carry out 5 seconds of work each should take 5 seconds total. So what happens if we take out the concept of multithreading? How long would this process take? We it would have to create each Worker one at a time and have each one carry out their work in a linear fashion, so it would take 25 seconds to complete. So technically, by implementing multithreading here, we have increased the speed of our processes by 500%! Not too shabby.