This is the first day of my participation in the August More text Challenge. For details, see: August More Text Challenge

Various lock information in Juc

The JUC package in Java gives us all kinds of lock information. If you look carefully, most of them implement an interface called LOCK. This article will help you review the LOCK information;

In this article, you will learn the following: 1. A comparison of Lock and synchronized; 2. A summary of common APIS used in Lock

Synchronized faces disadvantages

Locks occur primarily to ensure that concurrent access to shared resources does not occur. In Java, adding the Synchrionzed keyword to shared resource information solves most of the concurrency problems, but it also comes with flexibility and efficiency:

Efficiency:

1. In this case, few locks are released, which leads to exclusive resources and performance degradation. 2. We cannot specify conditions directly when trying to acquire a lock. 3. We cannot interrupt a thread trying to acquire a lockCopy the code

Flexibility:

2. The lock information is released only when the program is abnormal or successfully executed. There is no time to release the lock actively.Copy the code

Scenarios that are not applicable

Scenario 1:

When we use synchronized, if one thread acquired a lock and then blocked because it was waiting for IO or other reasons, and did not release the lock information, then the other thread would have to wait. Synchronized has a mechanism to keep waiting threads from waiting indefinitely.

Scenario 2:

In the form of read file information, write operations of different threads are conflicting. But read operations do not cause conflicts. If we add the synchronized keyword to the resource information without consideration, then when multiple threads operate simultaneously, only one thread can acquire the resource, and other threads that do not acquire the lock information can only enter the wait state, resulting in low read and write efficiency.

The Lock interface

The Lock interface is an addition and extension to the synchronized keyword, which allows us to share resource information with more flexibility in a thread-safe manner.

Common usage:

Lock Best practices:

1.lock(),unlock()

In general, Lock must be used within the try… The catch… Block, and the operation of releasing the lock takes place in the finally block. This is because lock does not release the lock in case of an exception, as synchronized does, so you must ensure that there is a manual release process so that other threads have a chance to acquire the lock.

The lock (); / / lock lock. Try {// process the task}catch(Exception ex){}finally{// Release the lock(ina finally block, so that the lock information is always released) lock.unlock(); }Copy the code

2. tryLock() & tryLock(long time, TimeUnit unit)

The tryLock() method returns a value that is used to attempt to acquire the lock, and returns true on success; If the acquisition fails (that is, the lock was acquired by another thread), then false is returned. That is, the method returns immediately anyway even if it fails to acquire the lock and does not wait consistently.

The tryLock(long time, TimeUnit Unit) method is similar to the tryLock() method, except that it waits a certain amount of time before it can get the lock, and returns false if it can’t get the lock within that time

Returns true if the lock was acquired initially or during the wait period. In general, tryLock is used to acquire a lock:

Lock lock = ... ; If (lock.trylock ()) {try{// process the task}catch(Exception ex){}finally{lock.unlock(); // Release the lock}}else {// If the lock cannot be acquired, do something else directly}Copy the code

3. lockInterruptibly()

The lockInterruptibly() method is special in that when a lock is acquired through this method, if the thread is waiting to acquire the lock, the thread can respond to an interruption, which interrupts the thread’s wait state.

For example, if two threads want to acquire A lock through lock.lockinterruptibly () at the same time, if thread A acquires the lock and threadB is only waiting, then calling threadb.interrupt () on threadB can interrupt the wait.

public void method() throws InterruptedException { lock.lockInterruptibly(); try { //..... } finally { lock.unlock(); }}Copy the code

When a thread acquies a lock, it is not interrupted by the interrupt() method. The interrupt() method can only interrupt a thread in a blocking process, not a thread in a running process. In synchronized, when a thread is in a state of waiting for a lock, it can’t be interrupted, it can only wait, which is why we need to release the lock manually.

To verify this, give the following example: Create two threads to compete for lock information

public class LockInterruptibly implements Runnable { private Lock lock = new ReentrantLock(); public static void main(String[] args) { LockInterruptibly lockInterruptibly = new LockInterruptibly(); Thread thread0 = new Thread(lockInterruptibly); Thread thread1 = new Thread(lockInterruptibly); thread0.start(); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } thread1.start(); thread1.interrupt(); } @override public void run() {system.out.println (thread.currentThread ().getName() + "Try to get the lock "); try { lock.lockInterruptibly(); Try {system.out.println (thread.currentThread ().getName() + "Got the lock "); Thread.sleep(5000); } catch (InterruptedException e) {system.out.println (thread.currentThread ().getName() + "Interrupted during sleep "); } finally { lock.unlock(); System.out.println(thread.currentThread ().getName() + "Release the lock "); }} catch (InterruptedException e) {system.out.println (thread.currentThread ().getName() + "The lock acquisition was interrupted "); }}}Copy the code
Result: Thread-0 attempted to obtain the lock thread-0 obtained the lock. Thread-1 attempted to obtain the lock. The lock acquisition by thread-1 was interrupted, and thread-0 released the lockCopy the code

From the resulting information, we can see that lockInterruptibly () interrupts only the waiting thread information, but not the running thread.

Compare the difference between Lock and tryLock

Both Lock and tryLock can obtain lock information, but there are some differences between the two. The details are as follows:

1: If lock fails to get the lock, it will wait forever. TryLock is to try, return false if you don’t get it, return true if you get it.

2: tryLock is interruptible, interrupted, lock is not.

Public class LockDemo implements Runnable{static Lock lock1 = new ReentrantLock(); @override public void run() {// lock1.lock(); lock1.tryLock(); System.out.println(" Thread "+ thread.currentThread ().getName() +" get lock information "); } public static void main(String[] args) throws InterruptedException { LockDemo r1 = new LockDemo(); LockDemo r2 = new LockDemo(); r1.flag = true; r2.flag = false; Thread t1 = new Thread(r1); Thread t2 = new Thread(r2); t1.start(); Thread.sleep(1000); / / the interrupt t2. Start (); t2.interrupt(); }}Copy the code

Result Information:

Output when lock1.lock () is executed: you can see that the lock method does not respond to interrupt information, and the lock information is held consistently if the lock is not held!

For tryLock it can respond to interrupts

conclusion

This article analyzes and summarizes the apis commonly used in Lock interfaces, as well as the relationship between Lock interfaces and synchronized keys.