The code segments within a program that access the same object from separate, concurrent threads are called critical sections. In the Java language, a critical section can be a block or a method and are identified with the
Sample Code
In the producer/consumer example, the
Here's a code skeleton for the
See also class level lock vs instance level lock.
synchronized
keyword. The Java platform then associates a lock with every object that has synchronized code.Sample Code
In the producer/consumer example, the
put
and get
methods of the CubbyHole
are the critical sections. The Consumer
should not access the CubbyHole
when the Producer
is changing it, and the Producer
should not modify it when the Consumer
is getting the value. So put
and get
in the CubbyHole
class should be marked with the synchronized
keyword. Here's a code skeleton for the
CubbyHole
class:Note that the method declarations for bothpublic class CubbyHole {
private int contents;
private boolean available = false;
public synchronized int get() {
...
}
public synchronized void put(int value) {
...
}
}
put
and get
contain the synchronized
keyword. Hence, the system associates a unique lock with every instance of CubbyHole
(including the one shared by the Producer
and the Consumer
). Whenever control enters a synchronized method, the thread that called the method locks the object whose method has been called. Other threads cannot call a synchronized method on the same object until the object is unlocked. So, when the Producer
calls CubbyHole
's put
method, it locks the CubbyHole
, thereby preventing the Consumer
from calling the CubbyHole
's get
method: When thepublic synchronized void put(int value) {
// CubbyHole locked by the Producer
..
// CubbyHole unlocked by the Producer
}
put
method returns, the Producer
unlocks the CubbyHole
. Similarly, when the Consumer
calls CubbyHole
's get
method, it locks the CubbyHole
, thereby preventing the Producer
from calling put
: The acquisition and release of a lock is done automatically and atomically by the Java runtime system. This ensures that race conditions cannot occur in the underlying implementation of the threads, thus ensuring data integrity. Synchronization isn't the whole story. The two threads must also be able to notify one another when they've done their job. Learn more about that after a brief foray into reentrant locks.public synchronized int get() {
// CubbyHole locked by the Consumer
...
// CubbyHole unlocked by the Consumer
}
See also class level lock vs instance level lock.
No comments:
Post a Comment