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

Java provides synchronized. Why provide Lock?

2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

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

This article mainly explains why Java provides synchronized but also provides Lock. Interested friends may wish to have a look. The method introduced in this paper is simple, fast and practical. Let's let the editor take you to learn "Why does Java provide Lock when it provides synchronized?"

Reinvent the wheel?

Since the synchronized keyword is provided in JVM to ensure that only one thread can access the synchronous code block, why provide the Lock interface? Is this a repeat of the wheel? Why would the designers of Java do this? Let's look down with questions.

Why provide Lock interface?

Many friends may have heard that the performance of synchronized is not as good as that of Lock in Java 1.5, but after Java 1.6, synchronized has made a lot of optimizations and performance has improved a lot. So why use Lock when the performance of the synchronized keyword has improved?

If we think deeper, it is not difficult to think: we can not actively release the lock using synchronized locking, which will involve the problem of deadlock.

Deadlock problem

If a deadlock is to occur, there must be the following four necessary conditions, none of which are indispensable.

Mutually exclusive condition

A resource is occupied by only one thread for a period of time. At this point, if another thread requests the resource, the requesting thread can only wait.

Inalienable condition

The resource obtained by the thread cannot be forcibly taken away by other threads before it is used up, that is, it can only be released by the thread that acquired the resource itself (only actively released).

Request and hold condition

The thread has maintained at least one resource, but a new resource request has been made, and the resource has been occupied by another thread, and the requesting thread is blocked, but holds on to the resources it has acquired.

Cyclic waiting condition

When a deadlock occurs, there must be a process waiting queue {P _ 1 ~ P _ 2, … , Pn}, where P1 waits for the resources occupied by P2, and P2 waits for the resources occupied by P3. Pn waits for the resources occupied by P1 to form a process waiting loop, in which the resources occupied by each process are simultaneously applied by another, that is, the former process occupies the affectionate resources of the latter process.

Limitations of synchronized

If our program has a deadlock using the synchronized keyword, the synchronized key cannot break the condition of the deadlock. This is because when synchronized applies for resources, if the application fails, the thread directly enters the blocking state, and the thread enters the blocking state, which can do nothing and can not release the resources already occupied by the thread.

However, in most scenarios, we hope that the condition of "inalienable" can be broken. That is to say, for the condition of "inalienable", when a thread that occupies part of a resource further applies for other resources, if it fails to apply, it can actively release the resources it occupies, so that this condition can not be deprived.

If we redesigned the locks ourselves to solve the synchronized problem, how should we design them?

Solve the problem

After understanding the limitations of synchronized, how do we design it if we are asked to implement a synchronization lock ourselves? In other words, when we design locks, how can we solve the limitations of synchronized? Here, I think we can think about this problem from three aspects.

(1) be able to respond to interrupts. The problem with synchronized is that after holding lock A, if the attempt to acquire lock B fails, the thread enters a blocking state, and once a deadlock occurs, there is no chance to wake up the blocked thread. But if the blocking thread can respond to the interrupt signal, that is, when we send an interrupt signal to the blocked thread, it can wake it up, then it has a chance to release lock An it once held. This undermines the inalienable conditions.

(2) timeout is supported. If the thread does not acquire the lock for a period of time, instead of entering the blocking state, it returns an error, then the thread also has a chance to release the lock it once held. This can also destroy the inalienable conditions.

(3) acquire the lock non-blocking. If the attempt to acquire the lock fails and does not enter the blocking state, but returns directly, then the thread also has a chance to release the lock it once held. This can also destroy the inalienable conditions.

Reflected in the Lock interface, there are three methods provided by the Lock interface, as shown below.

/ / support interrupted API

Void lockInterruptibly () throws InterruptedException

/ / support timed-out API

Boolean tryLock (long time, TimeUnit unit) throws InterruptedException

/ / API that supports non-blocking acquisition of locks

Boolean tryLock ()

LockInterruptibly ()

Support interruption.

TryLock () party k

The tryLock () method has a return value, which indicates that it is used to attempt to acquire the lock, returns true if the acquisition is successful, and returns false if the acquisition fails (that is, the lock has been acquired by another thread), which means that the method will return immediately anyway. You don't always wait there when you can't get the lock.

TryLock (long time, TimeUnit unit) method

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 the lock is not available, and returns false if the lock is not available within the time limit. If you get the lock at first or during the wait, return true.

That is to say, for the deadlock problem, Lock can break the inalienable condition, for example, our following program code breaks the inalienable condition of the deadlock.

Public class TansferAccount {

Private Lock thisLock = new ReentrantLock ()

Private Lock targetLock = new ReentrantLock ()

/ / account balance

Private Integer balance

/ / transfer operation

Public void transfer (TansferAccount target, Integer transferMoney) {

Boolean isThisLock = thisLock.tryLock ()

If (isThisLock) {

Try {

Boolean isTargetLock = targetLock.tryLock ()

If (isTargetLock) {

Try {

If (this.balance > = transferMoney) {

This.balance-= transferMoney

Target.balance + = transferMoney

}

} finally {

TargetLock.unlock

}

}

} finally {

ThisLock.unlock ()

}

}

}

}

As an exception, there is a ReentrantLock under Lock, while ReentrantLock supports both fair and unfair locks.

When using ReentrantLock, there are two constructors in ReentrantLock, one is a no-parameter constructor, and the other is a constructor that passes in a fair parameter. The fair parameter represents the fair policy of the lock. If true is passed, it means that a fair lock needs to be constructed. Otherwise, it means that an unfair lock needs to be constructed. As shown in the following code snippet.

/ / No parameter constructor: default unfair lock

Public ReentrantLock () {

Sync = new NonfairSync ()

}

/ / create locks based on fairness policy parameters

Public ReentrantLock (boolean fair) {

Sync = fair? New FairSync (): new NonfairSync ()

}

The implementation of the lock essentially corresponds to an entry waiting queue. If a thread does not acquire the lock, it will enter the waiting queue. When a thread releases the lock, it needs to wake up a waiting thread from the waiting queue. If it is a fair lock, the wake-up strategy is to wake up whoever waits for a long time, which is fair; if it is an unfair lock, it will not provide this fair guarantee, and it is possible that threads with short waiting time will be awakened first. Lock supports fair locking, while synchronized does not support fair locking.

Finally, it is worth noting that when using Lock locking, be sure to release the lock in the finally {} code block, for example, as shown in the following code snippet.

Try {

Lock.lock ()

} finally {

Lock.unlock ()

} at this point, I believe you have a deeper understanding of "Java provides synchronized why do you want to provide Lock"? you might as well do it in practice! Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!

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

Internet Technology

Wechat

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

12
Report