Use Lock, ReadWriteLock, and ReentrantLock classes in the java.util.concurrent.locks and java.util.concurrent.atomic packages to support lock-free thread-safe programming on single variables
The Lock
, ReadWriteLock
and ReentrantLock
classes and interfaces allow for different types of Locks. These Locks are used so that a limited number of threads have access to the same variable at any given time, or so that only one of them can change its value.
In this section examples will be presented using these classes and interfaces. As in other sections of this chapter, examples can be large when creating threads is required. Take more time to fully understand them.
-
You can get a Lock using the
ReentrantLock
class.src/org/j6toj8/concurrency/locks/Locks_ReentrantLock.javalink:../../../src/org/j6toj8/concurrency/locks/Locks_ReentrantLock.java[role=include]
console outputABC
Note that lock is removed within a
finally
block. This ensures that a thread will not have an lock indefinitely. -
Calling the unlock method without previously locking will throw an exception.
src/org/j6toj8/concurrency/locks/Locks_UnlockWithoutLock.javalink:../../../src/org/j6toj8/concurrency/locks/Locks_UnlockWithoutLock.java[role=include]
console outputABC Exception in thread "main" java.lang.IllegalMonitorStateException at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:151) at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1261) at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:457) at org.j6toj8.concurrency.locks.Locks_UnlockWithoutLock.main(Locks_UnlockWithoutLock.java:14)
-
You can try to get a lock immediately using the
tryLock
method.src/org/j6toj8/concurrency/locks/Locks_TryLock.javalink:../../../src/org/j6toj8/concurrency/locks/Locks_TryLock.java[role=include]
console outputABC
-
You can also try to get a lock by setting a maximum wait time.
src/org/j6toj8/concurrency/locks/Locks_TryLockTimeout.javalink:../../../src/org/j6toj8/concurrency/locks/Locks_TryLockTimeout.java[role=include]
console outputABC
-
In a scenario with multiple threads, only one of them may be able to obtain a lock.
src/org/j6toj8/concurrency/locks/Locks_TryLockMultithread.javalink:../../../src/org/j6toj8/concurrency/locks/Locks_TryLockMultithread.java[role=include]
console outputThread-0: Got the Lock Thread-2: Got the Lock
In this 3 threads run, only two were able to get lock immediately and print to the console. But the result is unpredictable. There may be executions where all will get the lock, and others where only one thread will succeed.
-
A thread can get more than one lock on the same
Lock
object, but must undo lock multiple times as well.src/org/j6toj8/concurrency/locks/Locks_LockTwice.javalink:../../../src/org/j6toj8/concurrency/locks/Locks_LockTwice.java[role=include]
console outputABC
Since the thread called the
lock
twice, if it had not calledunlock
twice, another thread would not be able to get the lock. -
You can ensure a more "fair" distribution of locks by passing
true
as an argument toReentrantLock
.src/org/j6toj8/concurrency/locks/Locks_Fair.javalink:../../../src/org/j6toj8/concurrency/locks/Locks_Fair.java[role=include]
When passing the
true
argument, when multiple threads are waiting for the same lock, it will be given to that thread that has been waiting the longest.
-
You can separate read and write locks using the
ReadWriteLock
class. Read Locks can be obtained by multiple threads, but write locks cannot.src/org/j6toj8/concurrency/locks/Locks_ReadWriteLock.javalink:../../../src/org/j6toj8/concurrency/locks/Locks_ReadWriteLock.java[role=include]
console outputThread-0: Got the read Lock Thread-2: Got the read Lock Thread-1: Got the read Lock Thread-1: Got the write Lock
Note that all threads were able to get read lock, but only one could get write lock.
-
If one thread already has write lock, others will not be able to get even read lock.
src/org/j6toj8/concurrency/locks/Locks_ReadWriteLockInverted.javalink:../../../src/org/j6toj8/concurrency/locks/Locks_ReadWriteLockInverted.java[role=include]
console outputThread-0: Got the write Lock Thread-0: Got the read Lock
Note that in this example the write lock is being obtained before read, so that only the first thread that was executed was able to get both locks.
-
Applying Locks
Boyarsky, Jeanne; Selikoff, Scott. OCP: Oracle Certified Professional Java SE 8 Programmer II Study Guide (p. 607). Wiley. Kindle Edition.
-
Package java.util.concurrent.locks. Java Plataform SE 8.