Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What are the methods of using the Lock interface

2025-03-31 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article introduces the relevant knowledge of "what are the methods of using the Lock interface". Many people will encounter such a dilemma in the operation of actual cases, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!

The Lock interface mainly consists of the following six methods

/ / acquire lock void lock () / / if the current thread is not interrupted, acquire the lock, and you can respond to the interrupt void lockInterruptibly () / / return the new Lock instance Condition newCondition () bound to this Condition instance / / acquire the lock only if the lock is idle at the time of call, in response to the interrupt boolean tryLock () / / if the lock is idle within a given waiting time and the current thread is not interrupted Then acquire lock boolean tryLock (long time, TimeUnit unit) / / release lock void unlock ()

Let's analyze each method in the Lock interface one by one. Lock (), tryLock (), tryLock (long time, TimeUnit unit), and lockInterruptibly () are all used to acquire locks. The unLock () method is used to release the lock. NewCondition () returns a new Condition instance bound to this Lock for inter-thread collaboration. For details, look for keywords: Inter-thread communication and collaboration.

1)。 Lock ()

Four methods are declared in Lock to acquire the lock, so what's the difference between these four methods? First of all, the lock () method is the most commonly used method, which is used to acquire locks. Wait if the lock has been acquired by another thread. As mentioned earlier, if you use Lock, you must take the initiative to release the lock, and if an exception occurs, the lock will not be released automatically. Therefore, generally speaking, using Lock must be done in try. Catch... Block, and the operation of releasing the lock is placed in the finally block to ensure that the lock must be released and prevent the occurrence of deadlock. Lock is usually used for synchronization in the following form:

Lock lock =...; lock.lock (); try {/ / processing task} catch (Exception ex) {} finally {lock.unlock (); / / release lock}

2)。 TryLock () & tryLock (long time, TimeUnit unit)

The tryLock () method has a return value, which indicates that it is used to attempt to acquire the lock, and if it is successful, it returns true;. If the acquisition fails (that is, the lock has been acquired by another thread), it returns false, that is, the method will return immediately anyway (it will not wait there all the time when the lock is not available).

The tryLock (long time, TimeUnit unit) method is similar to the tryLock () method, except that this method waits for a certain amount of time when it cannot get the lock, returns false within the time limit, and responds to the interrupt. If you get the lock at first or during the wait, return true.

In general, you use the following when acquiring locks through tryLock:

Lock lock =.; if (lock.tryLock ()) {try {/ / processing tasks} catch (Exception ex) {} finally {lock.unlock (); / / release the lock} else {/ / if you can't get the lock, just do something else}

3)。 LockInterruptibly ()

The lockInterruptibly () method is special. When a lock is acquired by this method, if the thread is waiting to acquire the lock, the thread can respond to the interrupt, that is, interrupting the waiting state of the thread. For example, when two threads want to acquire a lock through lock.lockInterruptibly () at the same time, if thread An acquires the lock and thread B is only waiting, calling the threadB.interrupt () method on thread B can interrupt the waiting process of thread B.

Because an exception is thrown in the declaration of lockInterruptibly (), lock.lockInterruptibly () must be placed in the try block or throw InterruptedException outside the declaration that calls lockInterruptibly (), but the latter is recommended, as explained later. Therefore, the general use of lockInterruptibly () is as follows:

Public void method () throws InterruptedException {lock.lockInterruptibly (); try {/ /. } finally {lock.unlock ();}}

Note that when a thread acquires the lock, it is not interrupted by the interrupt () method. Because the interrupt () method can only interrupt threads that are blocking, not threads that are running. Therefore, when a lock is acquired through the lockInterruptibly () method, if it cannot be acquired, the interrupt can only be responded to if it is waiting. Compared with synchronized, when a thread is waiting for a lock, it cannot be interrupted, only waiting all the time.

The implementation class ReentrantLock of Lock

ReentrantLock, you can reenter the lock. ReentrantLock is the only class that implements the Lock interface, and ReentrantLock provides more methods. Here are some examples to learn how to use ReentrantLock.

Construction method (without parameters and with parameters true: fair lock; false: unfair lock):

/ * * Creates an instance of {@ code ReentrantLock}. * This is equivalent to using {@ code ReentrantLock (false)}. * / public ReentrantLock () {sync = new NonfairSync ();} / * * Creates an instance of {@ code ReentrantLock} with the * given fairness policy. * * @ param fair {@ code true} if this lock should use a fair ordering policy * / public ReentrantLock (boolean fair) {sync = fair? New FairSync (): new NonfairSync ();} import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock;public class LockThread {Lock lock = new ReentrantLock (); public void lock (String name) {/ / acquire lock lock.lock (); try {System.out.println (name + "get the lock") / / access the resources protected by this lock} finally {/ / release lock lock.unlock (); System.out.println (name + "release the lock");}} public static void main (String [] args) {LockThread lt = new LockThread (); new Thread (()-> lt.lock ("A")). Start () New Thread (()-> lt.lock ("B")). Start ();}}

From the execution results, it can be seen that both thread An and thread B lock the resource at the same time. After thread An acquires the lock, thread B has to wait until thread A releases the lock.

To sum up, Lock provides more functionality than synchronized. But pay attention to the following points:

1) synchronized is a keyword of the Java language, so it is a built-in feature. Lock is not built into the Java language. Lock is an interface that can be accessed synchronously through the implementation class.

2) synchronized is implemented at the JVM level, not only through some monitoring tools to monitor the lock of synchronized, but also when an exception occurs when the code is executed, JVM will automatically release the lock, but not with Lock. Lock is implemented through code. To ensure that the lock must be released, unLock () must be put into finally {}.

3) when the competition for resources is not very fierce, the performance of Synchronized is better than that of ReetrantLock, but in the case of fierce competition for resources, the performance of Synchronized will decline by dozens of times, but the performance of ReetrantLock can remain normal.

ReadWriteLock lock

There are only two methods for the ReadWriteLock interface:

/ / return lock Lock readLock () for read operation / / return lock Lock writeLock () for write operation

ReadWriteLock maintains a pair of related locks, one for read-only operations and the other for write operations. As long as there is no writer, read locks can be held by multiple reader threads at the same time, while write locks are exclusive.

Three threads read and write a shared data at the same time

Import java.util.Random;import java.util.concurrent.locks.ReadWriteLock;import java.util.concurrent.locks.ReentrantReadWriteLock;class Queue {/ / share data that can only be written by one thread, but can be read by multiple threads at the same time. Private Object data = null; ReadWriteLock lock = new ReentrantReadWriteLock (); / / read data public void get () {/ / read lock lock.readLock (). Lock (); try {System.out.println (Thread.currentThread (). GetName () + ">); Thread.sleep ((long) (Math.random () * 1000) System.out.println (Thread.currentThread (). GetName () + "have read data:" + data);} catch (InterruptedException e) {e.printStackTrace ();} finally {/ / release read lock lock.readLock (). Unlock ();}} / / write data public void put (Object data) {/ / write lock lock.writeLock (). Lock () Try {System.out.println (Thread.currentThread (). GetName () + "be ready to write data!"); Thread.sleep ((long) (Math.random () * 1000)); this.data = data; System.out.println (Thread.currentThread (). GetName () + "have write data:" + data);} catch (InterruptedException e) {e.printStackTrace () } finally {/ / release the write lock lock.writeLock (). Unlock ();} public class ReadWriteLockDemo {public static void main (String [] args) {final Queue queue = new Queue (); / / starts a total of 6 threads, 3 read threads, 3 write threads for (int I = 0; I)

< 3; i++) {//启动1个读线程new Thread() {public void run() {while (true) { queue.get(); } } }.start();//启动1个写线程new Thread() {public void run() {while (true) { queue.put(new Random().nextInt(10000)); } } }.start(); } }} 执行结果

Introduction to the related concepts of lock

1. Reentrant lock

If the lock is reentrant, it is called a reentrant lock. Like synchronized and ReentrantLock are reentrant locks, reentrancy, in my opinion, actually indicates the lock allocation mechanism: thread-based allocation, not method call-based allocation. For a simple example, when a thread executes a synchronized method, such as method1, and another synchronized method, method2, is called in method1, the thread does not have to reapply for the lock, but can execute the method method2 directly.

Class MyClass {public synchronized void method1 () {method2 ();} public synchronized void method2 () {}}

The two methods method1 and method2 in the above code are decorated with synchronized. If at some point thread An executes to method1, thread An acquires the lock of the object, and because method2 is also a synchronized method, thread A needs to reapply for the lock if synchronized is not reentrant. However, this results in a deadlock because thread An already holds a lock on the object and is applying for a lock on the object, so thread A waits for a lock that will never be acquired. Because both synchronized and Lock are reentrant, the above phenomenon will not occur.

2. Interruptible lock

As the name implies, an interruptible lock is a lock that responds to interrupts. In Java, synchronized is not an interruptible lock, while Lock is an interruptible lock.

If one thread An is executing the code in the lock and another thread B is waiting to acquire the lock, maybe because the waiting time is too long, thread B does not want to wait and wants to deal with something else first. we can let it interrupt itself or interrupt it in another thread, which is an interruptible lock. The interruptibility of Lock was demonstrated in the previous demonstration of the use of tryLock (long time, TimeUnit unit) and lockInterruptibly ().

3. Fair lock

Fair lock means to acquire the lock in the order in which the lock is requested. For example, if there are multiple threads waiting for a lock, and when the lock is released, the thread that waits the longest (the thread that requests first) will acquire the place. This is a fair lock. On the other hand, the unfair lock cannot guarantee that the lock will be acquired in the order in which the lock is requested, which may cause one or some threads to never acquire the lock.

In Java, synchronized is an unfair lock, and it cannot guarantee the order in which waiting threads will acquire locks. For ReentrantLock and ReentrantReadWriteLock, it is an unfair lock by default, but can be set to a fair lock

The other is to answer the question in the previous article (whether Lock is pessimistic lock or optimistic lock). For more information, please see java pessimistic lock and optimistic lock.

Let's first take a look at the Lock method of the class ReentrantLock

Public void lock () {sync.lock ();}

Then let's move on to the initialization of the sync object (here is the unfair lock)

Public ReentrantLock () {sync = new NonfairSync ();}

Then let's move on to the lock method of the class NonfairSync.

/ * Sync object for non-fair locks * / static final class NonfairSync extends Sync {private static final long serialVersionUID = 7316153563782823691L; / * * Performs lock. Try immediate barge, backing up to normal * acquire on failure. * / final void lock () {if (compareAndSetState (0,1)) setExclusiveOwnerThread (Thread.currentThread ()); else acquire (1);} protected final boolean tryAcquire (int acquires) {return nonfairTryAcquire (acquires);}}

Here's a compareAndSetState method. Let's keep tracking.

Protected final boolean compareAndSetState (int expect, int update) {/ / See below for intrinsics setup to support this return unsafe.compareAndSwapInt (this, stateOffset, expect, update);}

Here is not very familiar, here is called the compareAndSwapInt method of unsafe, that is to say, the implementation of the CAS algorithm.

We know that when ReentrantLock is created, there are fair locks and unfair locks. Let's see if fair locks also implement the CAS algorithm.

/ * * Creates an instance of {@ code ReentrantLock} with the * given fairness policy. * * @ param fair {@ code true} if this lock should use a fair ordering policy * / public ReentrantLock (boolean fair) {/ / fair=true is fair lock, fair=false is unfair lock sync = fair? New FairSync (): new NonfairSync ();}

Let's take a look at the source code of the FairSync class

/ * * Sync object for fair locks * / static final class FairSync extends Sync {private static final long serialVersionUID =-3000897897090466540L; final void lock () {acquire (1);} / * Fair version of tryAcquire. Don't grant access unless * recursive call or no waiters or is first. * / protected final boolean tryAcquire (int acquires) {final Thread current = Thread.currentThread (); int c = getState (); if (c = = 0) {if (! hasQueuedPredecessors () & & compareAndSetState (0, acquires)) {setExclusiveOwnerThread (current); return true }} else if (current = = getExclusiveOwnerThread ()) {int nextc = c + acquires; if (nextc < 0) throw new Error ("Maximum lock count exceeded"); setState (nextc); return true;} return false;}}

We can see that the lock method calls the acquire method, and after tracking it in, we find that there are a lot of logical judgments here. This is because the fair lock needs to judge the queue first-in-first-out and so on, and we ignore the others. Pay attention to the addWaiter method

Public final void acquire (int arg) {if (! tryAcquire (arg) & & acquireQueued (addWaiter (Node.EXCLUSIVE), arg) selfInterrupt ();}

By looking at the addWaiter source code, you can see that this method is useful to compareAndSetTail.

Private Node addWaiter (Node mode) {Node node = new Node (Thread.currentThread (), mode); / / Try the fast path of enq; backup to full enq on failure Node pred = tail; if (pred! = null) {node.prev = pred; if (compareAndSetTail (pred, node)) {pred.next = node; return node }} enq (node); return node;}

Looking at the compareAndSetTail source code, you can see that unsafe's compareAndSwapObject method is used here, so the fair lock of Lock still uses the CAS algorithm.

/ * CAS tail field. Used only by enq. * / private final boolean compareAndSetTail (Node expect, Node update) {return unsafe.compareAndSwapObject (this, tailOffset, expect, update);} "what are the methods of using the Lock interface"? thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report