Java 17 Recipes


Download 3.2 Mb.
Pdf ko'rish
bet190/245
Sana02.06.2024
Hajmi3.2 Mb.
#1839910
1   ...   186   187   188   189   190   191   192   193   ...   245
Bog'liq
Java 17 Recipes

 How It Works
If you have different structures that are required to be modified at the same time, you 
need to make sure that these structures are updated atomically. An atomic operation 
refers to a set of instructions that can be executed as a whole or none at all. An atomic 
operation is visible to the rest of the program only when complete.
In solution 1 (atomically modifying both the inventoryMap map and the 
customerOrders list), you pick a “principal” collection on which you lock 
(inventoryMap). Locking on the principal collection guarantees that if another thread 
tries to lock on the same principal collection, it must wait until the currently executing 
thread releases the lock on the collection.
Chapter 10 ConCurrenCy


371
Solution 2 is more explicit, offering an independent lock that coordinates the atomic 
operations instead of picking a principal collection. Locking refers to the ability of the 
JVM to restrict certain code paths to be executed by only one thread. Threads try to 
obtain the lock (locks are provided, for example, by a ReentrantLock instance, as shown 
in the example), and the lock can be given to only one thread at a time. If other threads 
were trying to acquire the same lock, they are suspended (WAIT) until the lock becomes 
available. The lock becomes available when the thread that currently holds the lock 
releases it. When a lock is released, it can then be acquired by one (and only one) of the 
threads waiting for that lock.
Locks are not “fair” by default. In other words, the order of the threads that requested 
the lock is not kept; this allows for very fast locking/unlocking implementation in the 
JVM, and in most situations, it is generally okay to use unfair locks. On a very highly 
contended lock, if there is a requirement to evenly distribute the lock (make it fair), you 
do so by setting the setFair property on the lock.
In solution 2, calling the inventoryLock.lock() method, either acquires the lock 
and continues or suspends execution (WAIT) until the lock can be acquired. Once the 
lock is acquired, no other thread can execute within the locked block. At the end of the 
block, the lock is released by calling inventoryLock.unlock().
When working with Lock objects (ReentrantLock, ReadLock, and WriteLock), it is 
common practice to surround the use of these Lock objects by a try/finally clause. 
After opening the try block, the first instruction would be to call the lock.lock() 
method. This guarantees that the first instruction executed is the acquisition of the lock. 
The release of the lock (by calling lock.unlock()) is done in the matching finally 
block. In the event of RuntimeException occurring while you have acquired the lock, 
unlocking within the finally clause assures that one doesn’t “keep” the lock and 
prevent other threads from acquiring it.
The use of the ReentrantLock object offers additional features that the synchronized 
statement doesn’t offer. For example, ReentrantLock has the tryLock() function, which 
attempts to get the lock only if no other threads have it (the method doesn’t make the 
invoking thread wait). If another thread holds the lock, the method returns false but 
continues executing. It is better to use the synchronized keyword for synchronization 
and use ReentrantLock only when its features are needed.
Chapter 10 ConCurrenCy


372
Tip While this is only a recipe book and proper threading techniques span their 
own volumes, it is important to raise awareness of deadlocks. Deadlocks occur 
when two locks are involved (acquired in reverse order within another thread). the 
simplest way to avoid a deadlock is to avoid letting the lock “escape.” this means 
that the lock, when acquired, should not execute code calling on other methods 
that could acquire a different lock. If that’s not possible, release the lock before 
calling such a method.
Be careful: any operation that refers to one or both collections needs to be protected 
by the same lock. Operations that depend on the result of one collection to query the 
second collection need to be executed atomically; they need to be done as a unit in 
which neither collection can change until the operation is completed.

Download 3.2 Mb.

Do'stlaringiz bilan baham:
1   ...   186   187   188   189   190   191   192   193   ...   245




Ma'lumotlar bazasi mualliflik huquqi bilan himoyalangan ©fayllar.org 2024
ma'muriyatiga murojaat qiling