In the previous laboratory, you have learnt how to create multiple threads in a Java program through extending the Thread class. Though this is quite useful, you may not want to do this in some applications. You may lose some freedom in designing your code by having your class a subclass of the Thread class. In this laboratory, we will learn an alternative method for creating threads.
The purpose of this laboratory is to :
In this approach, your class will implement the java.lang.Runnable interface. The Runnable interface consists of a single method, run(): your class must provide an implementation of it. This new run() method provides an entry point into your thread's execution. Your class is not a specialisation of the Thread, but you can obtain a reference to the thread by passing your Runnable object to a constructor of class Thread.
Here is an example program which creates two threads using the above ideas. This program performs the same tasks as the one you studied in the previous laboratory. You should be able to understand the details by yourself. However, here are some points to note :
Now we will try to study the different attempts for solving the mutual exclusion problem discussed in the lectures. We will study the first and second attempts in this lab. To remind you about these attempts, the first attempt uses a single variable called Turn to coordinate access to the critical section. The problem with this solution was that a process could starve if there is no contention. In other words, if process1 does not want to enter the critical section, process0 cannot enter the critical section and vice versa. I will explain below the details of the three files needed to program this solution.
MyObject.java. This is the base class which we will use in our programs.It has some useful methods like age() which determines the age of the current object of this or other inherited classes, getName() returns the name of the current object or thread, random() to return a random number and nap() to make the current thread sleep for a specified amount of time and also to report the duration of the sleep.
Attempts.java. In our solutions (or wrong solutions!), our processes (we will call them process but actually they are threads) execute the following loop. They first nap inside the non-critical section, then they express their desire to enter the critical section and once successful, they nap inside the critical section. They don't do anything useful since we are not interested in what they do inside their critical or non-critical sections. So we make them just sleep.
This file contains two classes: Process and MutualExclusion. We create threads by the method you have learnt today, ie by implementing the runnable interface.
The constructor Process takes several arguments which are easy to understand from their names, except the last one. The argument att is an object of the Attempt1 class. We will create different classes for different attempts for solving the mutual exclusion problem. We will explain this class in a moment. The variables napInsideCS and napOutsideCS are seeds for the random number generator which will determine the duration of sleep.
The methods insideCS and outsideCS simply make the thread sleep for sometime inside and outside the critical section. The run() method will provide the run() method required by the runnable interface. It simply calls the wantToEnterCS() and finishedInCS() methods of the Attempt1 class through the att object.
The MutualExclusion classcontains the main() method. It simply prints some messages, creates two threads (or processes if you like) by creating two instances of the Process class and passing the att object.
Attempt1.java. This is our first attempt almost directly from the book or the lecture notes. You should be able to follow the methods.
MyObject.java, Attempts.java and Attempt1.java. You will need to split Attempts.java into two classes.
Invoke the main method from MutualExclusion.
Study the output. The messages will show the strict alternation which we should expect. Now, try to change the program in such a way that a process will not be able to enter the critical section.
Hint: One way of doing this is to change the run method in Attempts.java. You can change the delays at different places in MyObject by assigning a value directly to the variable napping. Also, you can stop a thread by this call :Thread.currentThread().stop() You can extract the id of the currently running thread through this.id
Here is a skeleton for Attempt2.java You have to supply the details of the methods.
Also, make the necessary changes in Attempts.java when you create Attempt2.java.
Compile and run it.
Remember that in this solution, both the processes may enter the critical section simultaneously. Do you see that? If you don't see, create a situation where both of them are in the critical section.