Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Java Multithreading


Published on

Published in: Technology, News & Politics
  • Be the first to comment

  • Be the first to like this

Java Multithreading

  1. 1. Overview Let’s get the basics of multi- threaded programming in Java, and then write some simple programs. An Introduction to Multi-threading 12 MARCH 2008 | LINUX FoR YoU | cmyk
  2. 2. Overview I n a typical application like a word created in main). processor, many tasks need to be executed in parallel—for instance, responding to Asynchronous execution the user, checking spellings, formatting, Note that created threads run ‘asynchronously’. This displaying, saving, etc. These tasks can means that threads do not run sequentially (like function run as different processes, sharing the resources calls); rather, the order of execution of threads is not using inter-process communication. Multi-processing predictable. To understand this, let us extend our simple is heavyweight and costly in terms of the system calls program here: made, and requires a process switch. An easier and cheaper alternative is to use threads. class MyThread extends Thread { Multiple threads can run in the context of the same public void loop() { process and hence share the same resources. A context for(int i = 0; i < 3; i++) { switch is enough to switch between threads, whereas a System.out.println(“In thread “ + costly process switch is needed for processes. Thread.currentThread().getName() + Java has support for concurrent programming and “; iteration “ + i); has support for multi-threading in both language and try { library levels. In this article, we’ll cover the basics of Thread.sleep((int)Math.random()); multi-threaded programming in Java and write some } simple programs. We’ll also look at some difficult catch(InterruptedException ie) { problems that can crop up when we write multi- ie.printStackTrace(); threaded code. } } The basics } A Java thread can be created in two ways: by implementing the Runnable interface or by extending public void run() { the Thread class. Both have a method called run. This System.out.println(“This is new thread”); method will be called by the runtime when a thread this.loop(); starts executing. } A thread can be created by invoking the start method on a Thread or its derived objects. This in turn calls the public static void main(String args[]) throws Exception { run method and keeps the thread in running state. Now MyThread mt = new MyThread(); let us look at a simple example using threads. mt.start(); System.out.println(“This is the main Thread”); class MyThread extends Thread { mt.loop(); public void run() { } System.out.println(“This is new thread”); } } In a sample run, the output was: public static void main(String args[]) throws Exception { MyThread mt = new MyThread(); This is the main Thread mt.start(); In thread main; iteration 0 System.out.println(“This is the main Thread”); This is new thread } In thread Thread-0; iteration 0 } In thread Thread-0; iteration 1 In thread main; iteration 1 This program prints: In thread Thread-0; iteration 2 In thread main; iteration 2 This is the main Thread This is new thread In this program, we have a loop method that has a for loop that has three iterations. In the for loop, we print In this example, the MyThread class extends the the name of the thread and the iteration number. We can Thread class. We need to override the run method set and get the name of the thread using setName and in this class. This run method will be called when the getName methods, respectively. If we haven’t set the thread runs. In the main function, we create a new name of the thread explicitly, the JVM gives a default thread and start it. The program prints messages name (‘main’, ‘Thread-0’, ‘Thread-1’, etc.). After printing from both the main thread and the mt thread (that we this information, we force the current thread to sleep for | LINUX FoR YoU | MARCH 2008 13 cmyk
  3. 3. Overview 10 milli-seconds. of the value Counter.count and when they update The main thread (‘main’) and the child thread the counter with Counter.count++, they need not (‘hread-0’) are executed independently. The output immediately reflect that value in the main memory. In is not fixed and the order of executing the iterations the next read operation of Counter.count, the local in the threads is not predictable. This is one of the value of Counter.count is printed. fundamental and important concepts to understand in Technically, this program has a ‘data race’. To avoid multi-threading. this problem, we need to ensure that the write and read operations are done together (‘atomically’) by a Data races single thread. How do we ensure that? It is by acquiring Threads share memory and they can concurrently a lock on the object. Only a single thread can acquire modify data. This can lead to unintuitive results and end a lock on an object at a time, and only that thread in ‘data races’. Here is an example of a data race: can execute the code protected by the lock (that code segment is known as a ‘critical section’). Until class Counter { then the other threads have to wait. Internally, this is public static long count = 0; implemented with monitors and the process is called as } locking and unlocking. class UseCounter implements Runnable { Thread synchronisation public void run() { Java has a keyword synchronised to acquire a lock. Lock for (int i = 0; i < 3; i++) { is not obtained on code, but on a resource. Any object Counter.count++; (not primitive types but of reference type) can be used System.out.print(Counter.count + “ “); to acquire a lock. } Here is an improved version of the code that provides } synchronised access to Counter.count, and does both } read and write operations on that in a critical section. For that, only the run method needs to be changed as public class DataRace { follows: public static void main(String args[]) { UseCounter c = new UseCounter(); public void run() { Thread t1 = new Thread(c); for (int i = 0; i < 3; i++) { Thread t2 = new Thread(c); synchronized(this) { Thread t3 = new Thread(c); Counter.count++; t1.start(); System.out.print(Counter.count + “ “); t2.start(); } t3.start(); } } } } The program now prints the expected output In this program, we have a Counter class, which has correctly: a static variable count. The UseCounter class simply increments the count and prints the count three times in 1 2 3 4 5 6 7 8 9 a for loop. We create three threads in the main function in the DataRace class and start it. We expect the In the run method, we acquire lock on the implicit program to print 1 to 9 sequentially as the threads run this pointer before doing both reading and writing to and increment the counters. However, when we run this Counter.count. program, it does print 9 integer values, but the output In this case, run is a non-static method. What about looks like garbage! In a sample run, I got these values: static methods, as they do not have this pointer? You can obtain a lock for a static method, and the lock is 3 3 5 6 3 7 8 4 9 obtained for the class instance and not the object. In fact, in this example, Counter.count is a static member, so we Note that the values will usually be different every might as well have acquired a lock on Counter.class for time you run this program. What is the problem? modifying and reading Counter.count. The expression Counter.count++ is a write operation and the next System.out.print statement Deadlocks has a read operation for Counter.count. When the Obtaining and using locks is tricky and can lead to lots three threads execute, each of them has a local copy of problems, one of which (a common one) is known as 14 MARCH 2008 | LINUX FoR YoU | cmyk
  4. 4. Overview a ‘deadlock’ (there are other problems like ‘livelocks’ Thread t2 = new Thread(c); and ‘lock starvation’ that are not discussed here). t1.start(); A deadlock happens when locking in threads t2.start(); results in a situation where they cannot proceed and } wait indefinitely for others to terminate -- for instance, } when one thread acquires a lock on resource, r1, and waits to acquire another resource, r2. At the same If you execute this program, it might run fine, or it time, there might be another thread that has already may deadlock and never terminate. acquired r2 and is waiting to obtain a lock on r1. Now, In this example, there are two classes, as you will notice, both the threads cannot proceed till Balls and Runs, with static member balls the other releases the lock, which never happens, so and runs. The Counter class has two they ‘deadlock’. methods IncrementBallAfterRun and Here is an example that programmatically shows IncrementRunAfterBall. They acquire locks on Balls. how this can happen. class and Runs.class in the opposite order. The run method calls these two methods consecutively. The class Balls { main method in the Dead class creates two threads public static long balls = 0; and starts them. } When the threads t1 and t2 execute, they will invoke the methods IncrementBallAfterRun and class Runs { IncrementRunAfterBall. In these methods, locks are public static long runs = 0; obtained in the opposite order. It might happen that t1 } acquires a lock on Runs.class and waits to acquire a lock on Balls.class. Meanwhile, t2 might have acquired class Counter implements Runnable { Balls.class and waits to acquire a lock on Runs.class. public void IncrementBallAfterRun() { So, this program can lead to a deadlock. It is not synchronized(Runs.class) { assured that this program will lead to a deadlock every synchronized(Balls.class) { time you execute this program. Why? We never know Runs.runs++; the sequence in which threads execute, and the order Balls.balls++; in which locks are acquired and released. For this } reason, the problems are said to be ‘non-deterministic’ } and such problems cannot be reproduced consistently. } We will not look at how to resolve this deadlock problem in this article. The objective is to introduce public void IncrementRunAfterBall() { you to problems like these that can occur in multi- synchronized(Balls.class) { threaded programs. synchronized(Runs.class) { In this article, we explored the basics of writing Balls.balls++; multi-threaded programming in Java. We can create Runs.runs++; classes that are capable of multi-threading by } implementing a Runnable interface or by extending } a Thread class. Concurrent reads and writes to } resources can lead to ‘data races’. Java provides thread synchronisation features for protected access public void run() { to shared resources. We need to use locks carefully. IncrementBallAfterRun(); Incorrect usage of lock can lead to problems like IncrementRunAfterBall(); deadlocks, livelocks or lock starvation, which are very } difficult to detect and fix. } By: S G Ganesh is a research engineer in Siemens public class Dead { (Corporate Technology), Bangalore. His latest book is ‘60 public static void main(String args[]) { Tips on Object Oriented Programming’ published by Tata Counter c = new Counter(); McGraw-Hill in December 2007. You can reach him at Thread t1 = new Thread(c); | LINUX FoR YoU | MARCH 2008 15 cmyk