Java Reference
In-Depth Information
To create a philosopher, you would use code like:
Lock fork1 = new ReentrantLock();
Lock fork2 = new ReentrantLock();
...
Lock fork5 = new ReentrantLock();
Philosopher p1 = new Philosopher(fork1, fork2, "John");
Philosopher p2 = new Philosopher(fork2, fork3, "Wallace");
...
Philosopher p5 = new Philosopher(fork5, fork1, "Charles");
It is left for the reader as an exercise to complete the code and run all five philosophers in five different threads to
simulate the dining-philosophers problem. You can also think about how to use the synchronized keyword to solve
the same problem. Read the code in the eat() method carefully. It tries to get the left and right forks one at a time. If
you can get only one fork and not the other, you put down the one you got so others can have it. The code in the eat()
method has only the logic to get the forks. In a real program, if you cannot get both forks, you would like to wait for
some time and try again to pick up the forks. You will have to write that logic.
You can specify the fairness of a lock when you instantiate the ReentrantLock class. The fairness indicates the
way of allocating the lock to a thread when multiple threads are waiting to get the lock. In a fair lock, threads acquire
the lock in the order they request it. In a non-fair lock, jumping ahead by a thread is allowed. For example, in a
non-fair lock, if some threads are waiting for a lock and another thread, which requests the same lock later, gets the
lock before the waiting threads if the lock becomes available at the time this thread requested it. This may sound a
little strange because it is not fair to the waiting threads to leave them waiting and granting the lock to the thread that
requested it later. However, it has a performance gain. The overhead of suspending and resuming a thread is reduced
using non-fair locking. The tryLock() method of the ReentrantLock class always uses a non-fair lock. You can create
fair and non-fair locks as follows:
Lock nonFairLock1 = new ReentrantLock(); // A non-fair lock (Default is non-fair)
Lock nonFairLock2 = new ReentrantLock(false); // A non-fair lock
Lock fairLock2 = new ReentrantLock(true); // A fair lock
A ReentrantLock provides a mutually exclusive locking mechanism. That is, only one thread can own the
ReentrantLock at a time. If you have a data structure guarded by a ReentrantLock , a writer thread as well as a reader
thread must acquire the lock one at a time to modify or to read the data. This restriction of ReentrantLock , to be
owned by only one thread at a time, may downgrade the performance if your data structure is read frequently and
modified infrequently. In such situations, you may want multiple reader threads to have concurrent access to the
data structure. However, if the data structure is being modified, only one writer thread should have the access to the
data structure. The Read-Write lock allows you to implement this kind of locking mechanism using an instance of the
ReadWriteLock interface. It has two methods: one to get the reader lock and another to get the writer lock, as shown:
public interface ReadWriteLock {
Lock readLock();
Lock writeLock();
}
A ReentrantReadWriteLock class is an implementation of the ReadWriteLock Interface. Only one thread can hold
the write lock of ReentrantReadWriteLock , whereas multiple threads can hold its read lock. Listing 6-32 demonstrates
the usage of ReentrantReadWriteLock . Note that in the getValue() method, you use read lock so multiple threads
can read the data concurrently. The setValue() method uses a write lock so only one thread can modify the data at a
given time.
Search WWH ::




Custom Search