Activity 8.5 - Testing locks and objects

Topic

This activity demonstrates that a lock is associated with an object, not a method.

Materials

In addition to the Solution document, the project for this activity contains the following class:

Task

The class BankAccount, is a modification of the class in Activity 8.4. It has a single data field balance, initialised to 0, and one synchronized method accessBalance(int threadID) which increments the balance by 1, then decrements it again, so that it there is no overall change and when the method exits the balance is again 0. Note that when the method is invoked the id number of the calling thread is passed as an argument.

Print statements report when the method is entered (with the balance at that point) and when it is exited, with the id of the thread concerned in both cases.

Your task will be to write two new classes, TestThread and Main, in order to experiment with a number of threads accessing a number of bank acccount objects.

Instructions

  1. Write a new class TestThread which extends Thread and has two data fields:

    The TestThread constructor should take two arguments and use them to initialise these fields.

    The run method of TestThread should contain a loop which invokes accessBalance(int threadID) on the bank account five times.

  2. Write a class Main which creates two BankAccount instances and two TestThread instances with id numbers 1 and 2 using different bank accounts, i.e. the bank accounts are not shared.

    Build and run the project (select the main class). You will probably get output that looks something like the following:

    Thread 1 entering access method - the balance is 0
    Thread 2 entering access method - the balance is 0
    Thread 1 exiting access method
    Thread 1 entering access method - the balance is 0
    Thread 2 exiting access method
    Thread 2 entering access method - the balance is 0
    Thread 1 exiting access method
    Thread 1 entering access method - the balance is 0
    etc.

    Both threads can execute the access method at once. This is because they are operating on different objects, and each object has its own separate lock. So even though the threads need to acquire these locks to run the synchronized method, they are not competing with one another for the same lock, and there is no reason why they cannot both be executing the same section of code concurrently.

    Since they are using different bank accounts the threads are looking at different data and can never see a balance that the other thread has temporarily incremented to 1. So the balance printed is always 0.

  3. Now alter accessBalance so that it is no longer declared synchronized. Re-compile and run the program. The change should make no difference! Since the threads are operating on distinct objects the presence or absence of a lock has no effect.

  4. Next amend Main so that both threads access the same bank account (still leaving accessBalance unsynchronized). Now when the program is run you should find that the threads can interfere with each other and will usually read the value of the balance while it is still set to 1.

  5. Lastly change accessBalance back to synchronized. This should correct the problem. The balance will now always be reported as 0. The threads are both using the same data object but can only access it one at a time.