Chapter 29 Multithreading
1
             Threads Concept
Multiple     Thread 1
threads on
             Thread 2
multiple
             Thread 3
CPUs
Multiple     Thread 1
threads
             Thread 2
sharing a
             Thread 3
single CPU
                               2
Using the Runnable Interface to Create
and Launch Threads
• Objective: Define a Task, create objects of Task and
  run in threads:
  • MyTask prints a text and sleeps for a while
   Interface Runnable {
     void run();
   }
   class MyTask implements Runnable {
   }
                                                         3
                         Creating Tasks and Threads
    java.lang.Runnable        TaskClass         // Client class
                                                public class Client {
                                                  ...
// Custom task class                              public void someMethod() {
public class TaskClass implements Runnable {        ...
  ...                                               // Create an instance of TaskClass
  public TaskClass(...) {                           TaskClass task = new TaskClass(...);
    ...
  }                                                  // Create a thread
                                                     Thread thread = new Thread(task);
    // Implement the run method in Runnable
    public void run() {                              // Start a thread
      // Tell system how to run custom thread        thread.start();
      ...                                            ...
    }                                               }
    ...                                             ...
}                                               }
                                                                                         4
                                   The Thread Class
     «interface»
 java.lang.Runnable
   java.lang.Thread
+Thread()                    Creates a default thread.
+Thread(task: Runnable)      Creates a thread for a specified task.
+start(): void               Starts the thread that causes the run() method to be invoked by the JVM.
+isAlive(): boolean          Tests whether the thread is currently running.
+setPriority(p: int): void   Sets priority p (ranging from 1 to 10) for this thread.
+join(): void                Waits for this thread to finish.
+sleep(millis: long): void   Puts the runnable object to sleep for a specified time in milliseconds.
+yield(): void               Causes this thread to temporarily pause and allow other threads to execute.
+interrupt(): void           Interrupts this thread.
                                                                                                       5
            The Static yield() Method
You can use the yield() method to temporarily release time
for other threads. For example, suppose you modify the
code in Lines 53-57 in TaskThreadDemo.java as follows:
   public void run() {
     for (int i = 1; i <= lastNum; i++) {
       System.out.print(" " + i);
       Thread.yield();
     }
   }
Every time a number is printed, the print100 thread is
yielded. So, the numbers are printed after the characters.
                                                        6
The Static sleep(milliseconds) Method
The sleep(long mills) method puts the thread to sleep for the
specified time in milliseconds. For example, suppose you modify the
code in Lines 53-57 in TaskThreadDemo.java as follows:
    public void run() {
      for (int i = 1; i <= lastNum; i++) {
        System.out.print(" " + i);
        try {
          if (i >= 50) Thread.sleep(1);
        }
        catch (InterruptedException ex) {
        }
      }
    }
Every time a number (>= 50) is printed, the print100 thread is put to
sleep for 1 millisecond.
                                                                  7
                        The join() Method
 You can use the join() method to force one thread to wait for another
 thread to finish. For example, suppose you modify the code in Lines
 53-57 in TaskThreadDemo.java as follows:
public void run() {                                      Thread           Thread
  Thread thread4 = new Thread(                          print100          printA
    new PrintChar('c', 40));
  thread4.start();                                    -char token     -char token
  try {
                                                      +getToken       +getToken
    for (int i = 1; i <= lastNum; i++) {              printA.join()
                                                      +setToken       +setToken
      System.out.print(" " + i);                      +paintCompo     +paintCompo
      if (i == 50) thread4.join();       Wait for printA
                                                    -char
                                                      net token       net
    }                                        to finish+mouseClicke    +mouseClicke
  }                                                 +getToken
                                                      d               d
  catch (InterruptedException ex) {      +getToken  +setToken         printA finished
  }                                      +setToken +paintCompone
                                                    t
                                         +paintComponet               -char token
}                                                   +mouseClicked
The numbers after 50 are printed after thread printA is finished.
                                                                                8
      Thread States
A thread can be in one of five states:
New, Ready, Running, Blocked, or
Finished.
                                          yield(), or                            Running
                                          time out                                                    run() returns
Thread created         start()
                 New              Ready                 run()         join()                                       Finished
                                                        interrupt()            sleep()
                                        Target                                               wait()
                                        finished
                                                        Wait for target         Wait for time         Wait to be
                                                          to finish                 out                notified
                                                                                         Time out           notify() or
                                                                                                            notifyAll()
                                                    Blocked
                                 Interrupted()
                                                                                                                      9
isAlive(), interrupt(), and isInterrupted()
The isAlive() method is used to find out the state of a
thread. It returns true if a thread is in the Ready, Blocked,
or Running state; it returns false if a thread is new and has
not started or if it is finished.
The interrupt() method interrupts a thread in the
following way: If a thread is currently in the Ready or
Running state, its interrupted flag is set; if a thread is
currently blocked, it is awakened and enters the Ready
state, and an java.io.InterruptedException is thrown.
The isInterrupt() method tests whether the thread is
interrupted.
                                                             10
                 Thread Priority
• Each thread is assigned a default priority of
  Thread.NORM_PRIORITY. You can reset the
  priority using setPriority(int priority).
• Some constants for priorities include
  Thread.MIN_PRIORITY
  Thread.MAX_PRIORITY
  Thread.NORM_PRIORITY
                                                  11
                    Thread Synchronization
A shared resource may be corrupted if it is
accessed simultaneously by multiple threads. For
example, two unsynchronized threads accessing
the same bank account may cause conflict.
  Step   balance   thread[i]                             thread[j]
  1      0         newBalance = bank.getBalance() + 1;
  2      0                                               newBalance = bank.getBalance() + 1;
  3      1         bank.setBalance(newBalance);
  4      1                                               bank.setBalance(newBalance);
                                                                                          12
       Example: Showing Resource Conflict
• Objective: Write a program that demonstrates the problem of
  resource conflict. Suppose that you create and launch one
  hundred threads, each of which adds a penny to an account.
  Assume that the account is initially empty.
     java.lang.Runnable
     -char token
                          100   1                                 1   1
       AddAPennyTask
     +getToken                         AccountWithoutSync                            Account
     +setToken
     +paintComponet                 -bank: Account                        -balance: int
     +mouseClicked
     +run(): void                   -thread: Thread[]
                                                                          +getBalance(): int
                                                                          +deposit(amount: int): void
                                    +main(args: String[]): void
                                                           AccountWithoutSync
                                                                      Run
                                                                                                        13
                                 Race Condition
What, then, caused the error in the example? Here is a possible scenario:
  Step    balance   Task 1                           Task 2
  1       0         newBalance = balance + 1;
  2       0                                          newBalance = balance + 1;
  3       1         balance = newBalance;
  4       1                                          balance = newBalance;
  );
The effect of this scenario is that Task 1 did nothing, because in
Step 4 Task 2 overrides Task 1's result. Obviously, the problem is
that Task 1 and Task 2 are accessing a common resource in a way
that causes conflict. This is a common problem known as a race
condition in multithreaded programs. A class is said to be thread-
safe if an object of the class does not cause a race condition in the
presence of multiple threads. As demonstrated in the preceding
example, the Account class is not thread-safe.
                                                                                 14
           The synchronized keyword
To avoid race conditions, more than one thread must be prevented
from simultaneously entering certain part of the program, known as
critical region. The critical region in the Listing 29.7 is the entire
deposit method. You can use the synchronized keyword to
synchronize the method so that only one thread can access the
method at a time. There are several ways to correct the problem in
Listing 29.7, one approach is to make Account thread-safe by adding
the synchronized keyword in the deposit method in Line 45 as
follows:
  public synchronized void deposit(double amount)
                                                                  15
     Synchronizing Instance Methods and Static
                      Methods
A synchronized method acquires a lock before it executes.
In the case of an instance method, the lock is on the object
for which the method was invoked. In the case of a static
method, the lock is on the class. If one thread invokes a
synchronized instance method (respectively, static method)
on an object, the lock of that object (respectively, class) is
acquired first, then the method is executed, and finally the
lock is released. Another thread invoking the same method
of that object (respectively, class) is blocked until the lock is
released.
                                                            16
   Synchronizing Instance Methods and Static
   Methods
With the deposit method synchronized, the preceding scenario
cannot happen. If Task 2 starts to enter the method, and Task 1 is
already in the method, Task 2 is blocked until Task 1 finishes the
method.
                              Task 1                                     Task 2
              Acquire a-char
                         locktoken
                               on the object account             -char token
                         +getToken                               +getToken
             -char token +setToken                               +setToken
                         +paintComponet                          +paintComponet
                     Execute
             +getToken        the deposit method
                         +mouseClicked                           +mouseClicked
             +setToken
             +paintComponet                                    Wait to acquire the lock
             -char token
             +mouseClicked
                                                        -char token
             +getToken    Release the lock
             +setToken
                                                         +getToken
             +paintComponet
             -char token                                 Acqurie a lock    on the object account
                                                         +setToken
             +mouseClicked
                                                         +paintComponet
             +getToken                                 -char token
                                                         +mouseClicked
             +setToken
             +paintComponet                                    Execute the deposit method
                                                       +getToken
             +mouseClicked                             +setToken
                                                       +paintComponet
                                                       -char token
                                                       +mouseClicked
                                                       +getToken    Release the lock
                                                       +setToken
                                                       +paintComponet
                                                                                                   17
                Synchronizing Statements
Invoking a synchronized instance method of an object acquires a lock
on the object, and invoking a synchronized static method of a class
acquires a lock on the class. A synchronized statement can be used to
acquire a lock on any object, not just this object, when executing a
block of the code in a method. This block is referred to as a
synchronized block. The general form of a synchronized statement is
as follows:
  synchronized (expr) {
    statements;
  }
The expression expr must evaluate to an object reference. If the
object is already locked by another thread, the thread is blocked until
the lock is released. When a lock is obtained on the object, the
statements in the synchronized block are executed, and then the lock
is released.
                                                                  18
     Synchronizing Statements vs. Methods
Any synchronized instance method can be converted into a
synchronized statement. Suppose that the following is a synchronized
instance method:
  public synchronized void xMethod() {
    // method body
  }
This method is equivalent to
  public void xMethod() {
    synchronized (this) {
      // method body
    }
  }
                                                               19
              wait(), notify(), and notifyAll()
Use the wait(), notify(), and notifyAll() methods to facilitate
communication among threads.
The wait(), notify(), and notifyAll() methods must be called in a
synchronized method or a synchronized block on the calling object of
these methods. Otherwise, an IllegalMonitorStateException would
occur.
The wait() method lets the thread wait until some condition occurs.
When it occurs, you can use the notify() or notifyAll() methods to
notify the waiting threads to resume normal execution. The
notifyAll() method wakes up all waiting threads, while notify() picks
up only one thread from a waiting queue.
                                                                  20