Home > Java > Multithreading > Introduction
Introduction

Introduction to Multithreading

A fundamental concept in computer programming is the idea of handling more than one task at a time. Many programming problems require that the program be able to stop what it’s doing, deal with some other problem, and then return to the main process. The solution has been approached in many ways. Initially, programmers with low-level knowledge of the machine wrote interrupt service routines and the suspension of the main process was initiated through a hardware interrupt. Although this worked well, it was difficult and nonportable, so it made moving a program to a new type of machine slow and expensive.

Sometimes interrupts are necessary for handling time-critical tasks, but there’s a large class of problems in which you’re simply trying to partition the problem into separately running pieces so that the whole program can be more responsive. Within a program, these separately running pieces are called threads, and the general concept is called multithreading. A common example of multithreading is the user interface. By using threads, a user can press a button and get a quick response rather than being forced to wait until the program finishes its current task.


The ability of an application to execute different parts of a program, called threads, simultaneously is called multithreading.

Ordinarily, threads are just a way to allocate the time of a single processor. But if the operating system supports multiple processors, each thread can be assigned to a different processor and they can truly run in parallel. One of the convenient features of multithreading at the language level is that the programmer doesn’t need to worry about whether there are many processors or just one. The program is logically divided into threads and if the machine has more than one processor then the program runs faster, without any special adjustments.

All this makes threading sound pretty simple. There is a catch: shared resources. If you have more than one thread running that’s expecting to access the same resource you have a problem. For example, two processes can’t simultaneously send information to a printer. To solve the problem, resources that can be shared, such as the printer, must be locked while they are being used. So a thread locks a resource, completes its task, and then releases the lock so that someone else can use the resource.

Java’s threading is built into the language, which makes a complicated subject much simpler. The threading is supported on an object level, so one thread of execution is represented by one object. Java also provides limited resource locking. It can lock the memory of any object (which is, after all, one kind of shared resource) so that only one thread can use it at a time. This is accomplished with the synchronized keyword. Other types of resources must be locked explicitly by the programmer, typically by creating an object to represent the lock that all threads must check before accessing that resource.

Syntax

class MyClass implements Runnable {

}

The preferred means of creating multithreaded Java applications is by implementing the Runnable interface (of package java.lang). A Runnable object represents a “task” that can execute concurrently with other tasks. The Runnable interface declares a single method, run, which contains the code that defines the task that a Runnable object should perform.


When a thread executing a Runnable is created and started, the thread calls the Runnable object’s run method, which executes in the new thread.

Example

1. /**
2. * @(#)MultithreadingDemo.java
3. *
4. *
5. * @author
6. * @version 1.00 2009/11/21
7. */
8.
9.  import java.util.Random;
10.
11.  class PrintTask implements Runnable  {
12.
13.    private final int sleepTime; // random sleep time for thread
14.    private final String taskName; // name of task
15.    private final static Random generator = new Random();
16.
17.     public PrintTask( String name ) {
18.        
19.         taskName = name; // set task name
20.
21.         // pick random sleep time between 0 and 5 seconds
22.         sleepTime = generator.nextInt( 5000 ); // milliseconds
23.    
24.     } // end PrintTask constructor
25.
26.     // method run contains the code that a thread will execute
27.     public void run() {
28.         
29.         // put thread to sleep for sleepTime amount of time
30.          try  {
31.            
32.             System.out.printf( "%s going to sleep for %d milliseconds.n", 

33.                        taskName, sleepTime );

34.
35.             Thread.sleep( sleepTime ); // put thread to sleep
36.        
37.         } // end try
38.         catch ( InterruptedException exception ) {
39.                
40.                 System.out.printf( "%s %sn", taskName,

41.                                         "terminated prematurely due to interruption" );

42.
43.         } // end catch
44.        
45.        // print task name
46.        System.out.printf( "%s done sleepingn", taskName );
47.
48.    } // end method run
49.
50. } // end class PrintTask        
51.
52. public class MultithreadingDemo {
53.        
54.    /**
55.     * Creates a new instance of MultithreadingDemo.
56.     */
57.    public MultithreadingDemo() {
58.    }
59.    
60.    /**
61.    * @param args the command line arguments
62.     */
63.   public static void main(String[] args) {
64.        // TODO code application logic here
65.        
66.       System.out.println( "Creating threads" );
67.        
68.        // create each thread with a new targeted runnable
69.        Thread thread1 = new Thread( new PrintTask( "task1" ) );
70.        Thread thread2 = new Thread( new PrintTask( "task2" ) );
71.        Thread thread3 = new Thread( new PrintTask( "task3" ) );
72.
73.        // create each thread with a new targeted runnable
74.        System.out.println( "Threads created, starting tasks." );
75.
76.        // start threads and place in runnable state
77.        thread1.start(); // invokes task1’s run method
78.        thread2.start(); // invokes task2’s run method
79.        thread3.start(); // invokes task3’s run method
80.
81.        // start threads and place in runnable state
82.        System.out.println( "Tasks started, main ends.n" );
83.
84.    }
85. }

Output

Creating threads
Threads created, starting tasks.
Tasks started, main ends.

task1 going to sleep for 3416 milliseconds.
task3 going to sleep for 2360 milliseconds.
task2 going to sleep for 2801 milliseconds.
task3 done sleeping
task2 done sleeping
task1 done sleeping

Class PrintTask implements Runnable (line 11), so that multiple PrintTasks can execute concurrently. Variable sleepTime (line 13) stores a random integer value from 0 to 5 seconds created in the PrintTask constructor (line 17). Each thread running a PrintTask sleeps for the amount of time specified by sleepTime, then outputs its task’s name and a message indicating that it’s done sleeping.

A PrintTask executes when a thread calls the PrintTask’s run method. Lines 32-33 display a message indicating the name of the currently executing task and that the task is going to sleep for sleepTime milliseconds. Line 35 invokes static method sleep of class Thread to place the thread in the timed waiting state for the specified amount of time. At this point, the thread loses the processor, and the system allows another thread to execute.

When the thread awakens, it reenters the runnable state. When the PrintTask is assigned to a processor again, line 46 outputs a message indicating that the task is done sleeping, then method run terminates. Note that the catch at lines 38–43 is required because method sleep might throw a (checked) InterruptedException if the sleeping thread’s interrupt method is called.

Main method creates Thread objects to execute PrintTasks. Lines 69–71 create three threads, each of which specifies a new PrintTask to execute. Lines 77–79 call Thread method start on each of the threads—each call invokes the corresponding Runnable’s run method to execute the task. Line 82 outputs a message indicating that all of the threads’ tasks have been started and that the main method is finished executing.

The code in method main executes in the main thread, a thread created by the JVM. The code in the run method of PrintTask (lines 27–48) executes in the threads created in lines 69–71. When method main terminates, the program itself continues running because there are still threads that are alive (i.e., any of the three threads we created that have not yet reached the terminated state). The program will not terminate until its last thread completes execution, at which point the JVM will also terminate.

Leave a Reply

Fields with * are mandatory.
* Name:
Website:
* Comments:
 
Tags allowed: <strong> <i> <u>
* Code:
 
 
Submit   Cancel