Locks
The java.util.concurrent.locks package provides support for locks, which are objects that offer an
alternative to using synchronized to
control access to a shared resource. In general, here is how a lock works.
Before accessing a shared resource, the lock that protects that resource is
acquired. When access to the resource is complete, the lock is released. If a
second thread attempts to acquire the lock when it is in use by another thread,
the second thread will suspend until the lock is released. In this way,
conflicting access to a shared resource is prevented.
Locks are particularly useful
when multiple threads need to access the value of shared data. For example, an
inventory application might have a thread that first confirms that an item is
in stock and then decreases the number of items on hand as each sale occurs. If
two or more of these threads are running, then without some form of
synchronization, it would be possible for one thread to be in the middle of a
transaction when the second thread begins its transaction. The result could be
that both threads would assume that adequate inventory exists, even if there is
only sufficient inventory on hand to satisfy one sale. In this type of
situation, a lock offers a convenient means of handling the needed synchronization.
The Lock interface defines a lock. The methods defined by Lock are shown in Table 28-1. In
general, to acquire a lock, call lock( ).
If the lock is unavailable, lock( )
will wait. To release a lock, call unlock(
). To see if a lock is available, and to acquire it if it is, call tryLock( ). This method will not wait
for the lock if it is unavailable. Instead, it returns true if the lock is acquired and false otherwise. The newCondition(
) method returns a Condition
object associated with the lock. Using a Condition,
you gain detailed control of the lock through methods such as await( ) and signal( ), which provide functionality similar to Object.wait( ) and Object.notify( ).
java.util.concurrent.locks supplies an implementation of Lock called ReentrantLock.
ReentrantLock implements a reentrant lock, which is a lock that can be repeatedly entered by the thread that currently holds the lock. Of course, in the
case of a thread reentering a lock, all calls to lock( ) must be offset by an equal number of calls to unlock( ). Otherwise, a thread seeking
to acquire the lock will suspend until the lock is not in use.
Method : Description
void lock( ) : Waits until
the invoking lock can be acquired.
void lockInterruptibly( )
throws InterruptedException : Waits until the invoking lock can be acquired,
unless interrupted.
Condition newCondition( ) :
Returns a Condition object that is associated with the invoking lock.
boolean tryLock( ) : Attempts
to acquire the lock. This method will not wait if the lock is unavailable.
Instead, it returns true if the lock has been acquired and false if the lock is
currently in use by another thread.
boolean tryLock(long wait,
TimeUnit tu) throws InterruptedException :
ttempts to acquire the lock. If the lock is unavailable, this method
will wait no longer than the period specified by wait, which is in tu units. It
returns true if the lock has been acquired and false if the lock cannot be
acquired within the specified period.
void unlock( ) : Releases the
lock.
Table
28-1 The Lock Methods
The following program
demonstrates the use of a lock. It creates two threads that access a shared
resource called Shared.count. Before
a thread can access Shared.count, it
must obtain a lock. After obtaining the lock, Shared.count is incremented and then, before releasing the lock,
the thread sleeps. This causes the second thread to attempt to obtain the lock.
However, because the lock is still held by the first thread, the second thread
must wait until the first thread stops sleeping and releases the lock. The
output shows that access to Shared.count
is, indeed, synchronized by the lock.
// A simple lock example.
import java.util.concurrent.locks.*;
class LockDemo {
public static void main(String args[]) { ReentrantLock
lock = new ReentrantLock();
new LockThread(lock, "A"); new
LockThread(lock, "B");
}
}
//A shared resource.
class Shared {
static int count = 0;
}
//A thread of execution that increments count.
class LockThread implements Runnable {
String name; ReentrantLock lock;
LockThread(ReentrantLock lk, String n) { lock =
lk;
name = n;
new Thread(this).start();
}
public void run() {
System.out.println("Starting " + name);
try {
// First, lock count.
System.out.println(name + " is waiting to
lock count."); lock.lock();
System.out.println(name + " is locking
count.");
Shared.count++;
System.out.println(name + ": " +
Shared.count);
// Now, allow a context switch -- if possible.
System.out.println(name + " is
sleeping.");
Thread.sleep(1000);
} catch (InterruptedException exc) {
System.out.println(exc);
} finally { // Unlock
System.out.println(name + " is unlocking
count."); lock.unlock();
}
}
}
The output is shown here.
(The precise order in which the threads execute may vary.)
Starting A
A is waiting to lock count.
A is locking count.
A: 1
A is sleeping.
Starting B
B is waiting to lock count.
A is unlocking count.
B is locking count.
B: 2
B is sleeping.
B is unlocking count.
java.util.concurrent.locks also defines the ReadWriteLock interface. This interface specifies a lock that maintains separate locks for read and write
access. This enables multiple locks to be granted for readers of a resource as
long as the resource is not being written. ReentrantReadWriteLock
provides an implementation of ReadWriteLock.
Related Topics
Privacy Policy, Terms and Conditions, DMCA Policy and Compliant
Copyright © 2018-2023 BrainKart.com; All Rights Reserved. Developed by Therithal info, Chennai.