CIS 35A: Introduction to Java Programming

Home | Green Sheet | Lectures | Assignments | FAQ | Grades

Threads

Threads
Synchronize threads
Create

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.

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 above example, the Account class is not thread-safe.

Concurrency and the need for synchronization

  • Whenever two or more threads can access an object, concurrency is an important issue.
  • Concurrency problems can result because a thread may be interrupted in the middle of the method it's running so that control can be given to another thread that runs the same method. When that happens, the intermediate results from the first thread can affect the accuracy of the second thread.

To avoid resource conflicts, Java uses the To avoid race conditions, more than one thread must be prevented from simultaneously entering certain part of the program, known as critical region. You can use the synchronized keyword to synchronize the method so that only one thread can access the method at a time.

The syntax for creating a synchronized method

{public|private} synchronized returnType methodName([parameterList])
{
    statements
}

How to create synchronized threads

  • The synchronized keyword assures that only one thread at a time is allowed to execute any synchronized method of an object by locking the object.
  • Any other thread that attempts to run any synchronized method for the object will be blocked until the first thread releases the lock by exiting the synchronized method.
  • A thread can run an unsynchronized method of an object even if the object is locked. That's because the object isn't checked for a lock unless a synchronized method is executed.
  • You should use synchronized methods whenever two or more threads might execute the same method. Even methods with just one line of code typically need to be synchronized.

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.

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.

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
  }
}

A synchronized method that calculates future values

public synchronized double calculateFutureValue(
    double monthlyPayment, double yearlyInterestRate,
    int years)
{
    int months = years * 12;
    double monthlyInterestRate =
        yearlyInterestRate/12/100;
    double futureValue = 0;
    for (int i = 1; i <= months; i++)
    {
        futureValue = (futureValue + monthlyPayment) *
                      (1 + monthlyInterestRate);
    }
    return futureValue;
}

A synchronized method that increments an instance variable

public synchronized int getInvoiceNumber()
{
    return invoiceNumber++;
}
Previous | Create | wait and notifyAll methods | Communicate among threads | Next