Listing 6-4 uses Lock 's lock() and unlock() methods to obtain and release a
lock. When a thread calls lock() and the lock is unavailable, the thread is disabled
(and cannot be scheduled) until the lock becomes available.
This listing also uses BlockingQueue 's offer() method instead of put() to
store an object in the blocking queue, and its poll() method instead of take() to
IfIhadused put() and take() ,thisapplicationwouldhavedeadlockedinthefol-
1. The consumer thread acquires the lock via its lock.lock() call.
2. The producer thread attempts to acquire the lock via its lock.lock() call
and is disabled because the consumer thread has already acquired the lock.
3. The consumer thread calls take() to obtain the next
java.lang.Character object from the queue.
4. Because the queue is empty, the consumer thread must wait.
before waiting, so the producer thread also continues to wait.
Note If I had access to the private lock used by BlockingQueue implementa-
tions, I would have used put() and take() , and also would have called Lock 's
lock() and unlock() methodsonthatlock.Theresultingapplication wouldthen
have been identical (from a lock perspective) to Listing 4-27 's PC application, which
used synchronized twice for each of the producer and consumer threads.
The java.util.concurrent.atomic package provides Atomic -prefixed
classes (e.g., AtomicLong ) that support lock-free, thread-safe operations on single
variables.Eachclassdeclaresmethodssuchas get() and set() toreadandwritethis
variable without the need for external synchronization.