Java Multithreading

by Trevor Page on January 4, 2013

Java MultithreadingToday I want to introduce the topic of Java multithreading to you. This is a bit of an advanced topic, so if you are not familiar with Java programming, I would recommend starting with the basics. If you have been around the Java programming block and have not yet tried your hand at multithreading, then that’s great! Let’s get started.

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 workers = new ArrayList();
    
    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.

Pitfalls of Java Multithreading

One thing I didn't touch on in this article is what's known as Synchronization, and this is the bane of the multithreading programmer's existence. This is because when you introduce the concept of multithreading, you are opening up the possibility of two Threads accessing/modifying the same Object in memory at the same time. When you try to do this, Java will throw an Exception. The solution to this problem is to synchronize access to your Objects so that no two Threads can trample over each other when trying to access any Object's properties/resources.

Another problem that arises with the use of Java multithreading is race conditions. This is when your code's output is based on a particular sequence of events, but with multithreading this is not a great idea, because you can't always guarantee that a particular set of events will happen in any particular order. Here's a wiki article explaining this problem: http://en.wikipedia.org/wiki/Race_condition.

I won't be touching on these concepts just yet, as I have already covered a lot for you to take in. The knowledge in this Java tutorial will be critical in completing the next Java practice assignment, so if you intend on completing it, be sure to understand what I'm explaining in this entire article.

{ 19 comments… read them below or add one }

Kris L January 4, 2013 at 7:43 pm

Phew! That’s some good info in there – looking forward to starting on the next practice assignment once I let my head cool for a moment. Keep up the awesome tutorials!

Reply

Javin Paul January 4, 2013 at 10:26 pm

Good post . I really like your assignment post , good work there. Importance of multi-threading is huge in Java space and correct understanding of threading concept is very important for any Java developer. Skill to find and avoid concurrency issues like thread-safety, deadlock and race conditions are getting increasingly important with programming on multi core processors. Cheers.

Reply

ararsa January 5, 2013 at 12:58 am

keep it up!!!!!!!!!!!!!

Reply

Bernd January 7, 2013 at 5:37 am

Very good post, Trevor.
One of my main problems in Java is understanding Exceptions.
So I searched for InterruptedException and found this article: http://www.ibm.com/developerworks/java/library/j-jtp05236/index.html
It states: “never swallow InterruptedException”, which your e.printStackTrace() does… (which never occured in my several test runs). What is your opinion?

Second: when running your second example, I *sometimes* get “The whole process took: 0 seconds.” followed by the 5 id messages.

Reply

Trevor Page January 7, 2013 at 10:14 am

Excellent question,

It’s true that you shouldn’t make a habit of “swallowing” exceptions. At the very least you should have an e.printStackTrace() so that you can see an error if it does occur (the exception stack trace will be printed to the console). If I were to be more thorough, I would likely output this message to a log and perhaps display it to the user, though usually displaying exceptions to the user is not the best choice. In the case of this example, I felt it wasn’t necessary to handle this exception.

To answer your second question, that is very odd… the only explanation I could come up with is that the Thread.sleep() code failed to work, were their exceptions in your console when it took 0 seconds?

Reply

Bernd January 7, 2013 at 11:36 am

1) the article states, you have to rethrow the InterruptedException, otherwise that Thread could possibly never end.

2) There were no exceptions at all, the main() thread always ends normally after 5 seconds (header line of the console window).
I’m using Java 1.6 and leave STS open all the time.
If I change the source code (add comments, etc.), the first run is always OK, but the the next runs will only be OK if I wait several minutes before the next run, otherwise the described behaviour occurs with main() ending after 5 seconds, too.
Java bug? Garbage collector?

Reply

Trevor Page January 7, 2013 at 1:05 pm

1) Nice, I’ve updated the source code to reflect these findings, thanks for pointing that out (I learn something new everyday).

2) It would be rare if it were a Java bug… I’m a bit stumped as to why this would happen.. I was thinking it could be something to do with synchronization (as that’s where most bugs in multithreading come from). I’m not able to reproduce the problem you’re talking about on my PC (I also keep STS open for days on end).

Reply

Bernd January 8, 2013 at 2:33 am

2) My environment:
Windows XP Sp3 32bit, all fixes. 4GB RAM, 1 CPU 2 cores, STS 3.1.0, jdk1.6.0_34

Just to be sure that I have not created a source error, I created a new class WorkerOrig, copied your source into it from above, replaced all “Worker” by “WorkerOrig”.
The result is absolutely random OK or BAD, has nothing to do with waiting time between runs or modifying/saving the source or restarting STS.

BAD result ( occuring after 5 seconds, no exception visible):
WorkerOrig[Java Application] …
This is currently running on the main thread, the id is: 1
This whole process took: 0 seconds.
This is currently running on a separate thread, the id is: 9
This is currently running on a separate thread, the id is: 11
This is currently running on a separate thread, the id is: 8
This is currently running on a separate thread, the id is: 10
This is currently running on a separate thread, the id is: 12

OK, as expected:
WorkerOrig[Java Application] …
This is currently running on the main thread, the id is: 1
This is currently running on a separate thread, the id is: 8
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: 12
This is currently running on a separate thread, the id is: 11
This whole process took: 5 seconds.

Bernd January 9, 2013 at 6:12 am

To complete this voodoo nightmare:

Today I installed JDK and STS and 2 fresh PCs.

a) Windows XP SP3 all fixes, 32bit, virual machine, 1 CPU, JDK 1.7 32bit, STS 3.1.0 32bit
Same bad random behaviour!

b) Windows 7, 64bit, 4 CPUs, 8 cores, JDK 1.7 64bit, STS 3.1.0 64bit:
Everything OK, no poblems.

Bernd January 9, 2013 at 8:35 am

Problem solved :-) (At least to my java beginner’s understanding…)

The key hint was the out of order thread id numbering in my BAD cases, in contrast to the ascending order in all OK cases. I realized, this is real multithreading, what this article is all about ;-)

Worker.running is public and initialized to false. If the check loop is performing its checks before Worker.run() has really started and had a chance to set running to true, it will be satisfied.

Reply

Trevor Page January 9, 2013 at 12:15 pm

Job well done.

I literally just ran into that case with Assignment 3 that I’m working on right now. I’m ironing out all the bugs in the unit tests that I’m writing for everyone, and this exact scenario was the culprit. Multithreading is very tricky and forces one to think outside the box!

Rashi August 26, 2013 at 1:23 am

Hi.. thank you for explaining the concept in such a simple manner but I was not able to locate the assignment for multithreading.

Reply

Simon January 23, 2014 at 5:29 am

Hi,

I quite a novice at this and I have a question. In the code, we are saying, we would sleep on the main thread for 100 milliseconds for EACH of the 5 worker objects.

// 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);
}
}

The worker threads sleep for 1 second EACH.

Does that not mean that in total, the process should take 5 seconds and 500 milliseconds?
I don’t understand why the “This whole process took: 5 seconds.”

Why is it necessary for the main thread to wait until the worker thread completes it work and why must it wait 100 milliseconds?

Reply

Trevor Page January 25, 2014 at 9:44 am

The trick here is to understand that there are 6 threads running simultaneously.

Thread 1 = Main thread
Threads 2-6 = Workers

So what will happen is the main thread (Thread 1) creates 5 new threads (Threads 2-6). The main thread (Thread 1) then waits any reasonable “unit of time” (In this case I chose 100 milliseconds, but I could have chosen 1 millisecond, or 10, or 25, or 50 etc. so long as it’s divisible by 5000) until the workers are done, then thread 1 reports its findings on how long the whole process took.

So if we were to lay it out on a timeline with the code I wrote, it may look something like this:

0 milliseconds -> Start main thread and start all worker threads
100 milliseconds -> main thread done sleeping, check if workers are done (they are not, it hasn’t been 5sec)
200 milliseconds -> main thread done sleeping, check if workers are done (they are not, it hasn’t been 5sec)
300 milliseconds -> main thread done sleeping, check if workers are done (they are not, it hasn’t been 5sec)
400 milliseconds -> main thread done sleeping, check if workers are done (they are not, it hasn’t been 5sec)
500 milliseconds -> main thread done sleeping, check if workers are done (they are not, it hasn’t been 5sec)

5000 milliseconds -> main thread done sleeping, check if workers are done (they ARE done working, as it’s been 5 seconds)
-> calculate how long it has taken to complete this process and report findings to console

Reply

Paul July 8, 2014 at 12:54 am

Thank you for insightful postst. Hey Trevor, could you please include the Runnable interface code as well?

Reply

Trevor Page July 9, 2014 at 10:59 am

The runnable interface is actually very boring, you can check it out via this website: http://docs.oracle.com/javase/7/docs/api/java/lang/Runnable.html

I believe all it looks like is this:

public interface Runnable
{
  public abstract void run();
}

Reply

Thio July 20, 2014 at 10:41 am

Hello Trevor,

I am still confused with your statement “each worker ‘sleeps’ for 5 seconds, this simulates 5 seconds of work that they are doing”. How can we say that sleep simulating 5 second of work? What I understand is calling “Thread.sleep()” will interrupt another thread to run, while doing a real work should not call another thread because otherwise the current thread will not process the work completely. Please correct me if I am wrong.

Thank you.

Reply

Trevor Page July 21, 2014 at 8:55 am

Good question Thio,

Invoking the Thread.sleep() method will not actually interrupt another thread to run, it will simply force the current Thread to pause and wait for the duration that you’ve specified. The reason why I used the sleep method as a “simulation of work” is because if I were to put actual “work” (like a bunch of calculations and loops or soemthing) into the mix, each computer would process that work differently and the results would vary for everyone.

I hope that helps clear things up, let me know if you still have questions though!

Reply

Ashish July 25, 2014 at 4:40 am

Threads can be implemented by extending Thread class, implementing Runnable interface and Callable interface.

If you want to return an value or throw an exception then use Callable otherwise use Runnable as extending Thread class limits the Class inheritance and also makes the process heavy.

Below link can be useful if you want to find more:
Different ways to implement Threads in Java

Reply

Leave a Comment

Powered by sweet Captcha

Previous post:

Next post: