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

How to avoid java deadlock

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

Share

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

This article mainly introduces "how to avoid java deadlock". In daily operation, I believe many people have doubts about how to avoid java deadlock. The editor consulted all kinds of data and sorted out simple and easy-to-use operation methods. I hope it will be helpful to answer the doubt of "how to avoid java deadlock"! Next, please follow the editor to study!

When you come to the bank and tell the teller that you want to transfer 100 copper to the iron egg, the teller turns to the wall to look for your account book and the iron egg's ledger. At this time, the teller may face three situations:

Ideal: you and the iron egg's ledger are free, take it back together, deduct 100 copper coins from your ledger, add 100 copper to the iron egg's ledger, and the teller turns around and hangs the ledger back on the wall to finish your business.

Awkward state: your account book is in, iron egg's account book is taken out by other tellers to transfer money to others, you have to wait for other tellers to return iron egg's account book.

Crazy state: your ledger is not there, nor is iron's ledger, so you can only wait for both ledgers to be returned.

Slow down the teller's withdrawal of the account book. He must first get your account book, and then go to get the iron egg's account book. After both account books are obtained (ideally), the transfer can be completed. Use the program model to describe the process of getting the account book:

Let's continue to describe the above model in program code:

Class Account {private int balance; / / transfer void transfer (Account target, int amt) {/ / lock transfer account synchronized (this) {/ / lock transfer account synchronized (target) {if (this.balance > amt) {this.balance-= amt; target.balance + = amt }}}

This solution looks good and solves the two problems mentioned at the beginning of the article, but is it really the case?

The ideal situation we just talked about is that the bank has only one teller (both single-threaded). As the size of the bank becomes larger, there are already many account books hanging on the wall. In order to cope with the busy business, the bank has opened multiple windows. At this time, there are multiple tellers (multi-threaded) to deal with the bank business.

Teller 1 is handling the business of transferring money to iron egg, but only gets your account book; teller 2 is handling the business of iron egg transferring money for you, but only getting iron egg's account book, at this time both sides are in an awkward state. Both tellers are waiting for each other to return the account book to handle the transfer business for the current customer.

In reality, the teller will communicate and shout out a voice, and the iron egg's account book will be used by me first and returned to you after use, but the program is not so smart. The synchronized built-in lock is very persistent, it will tell you the truth of "waiting for death", and eventually there will be a deadlock.

Java has synchronized built-in lock, but also invented the display lock Lock, is it just to cure synchronized's obsession with "death and so on"? ?

Solution

How to solve the above problems? As the saying goes, only when we know ourselves and the enemy can we win a hundred battles. We must first understand what will happen to deadlocks before we know how to avoid deadlocks. Fortunately, we can stand on the shoulders of giants and look at the problem.

Coffman summed up four conditions in which deadlocks can occur:

Coffman condition

Mutual exclusion condition: refers to the exclusive use of allocated resources by a process, that is, a resource is occupied by only one process for a period of time. If there are other processes requesting resources at this time, the requestor can only wait until the process in possession of the resource is released.

Request and retention condition: refers to that the process has maintained at least one resource, but has made a new resource request, and the resource has been occupied by other processes, and the requesting process is blocked, but does not let go of other resources it has acquired.

Inalienable condition: refers to the resources that have been acquired by the process, which cannot be deprived until they are used up, but can only be released by themselves at the end of use.

Loop waiting condition: when a deadlock occurs, there must be a ring chain of process-resources, that is, P1 in the process set {P1MaginP2, Pn} is waiting for a resource occupied by P2; P2 is waiting for the resource occupied by P3. Pn is waiting for resources that have been occupied by P0.

These conditions are easy to understand, in which the "mutex condition" is the foundation of concurrent programming, which cannot be changed. However, the other three conditions may be changed, that is to say, if the other three conditions are broken, the deadlock problem mentioned above will not occur.

Break request and hold conditions

Every teller can pick up and put in the account book, and it is easy to wait for each other. If you want to break the request and keep the condition, you need to get all the resources at once.

As a programmer, you must have heard this sentence:

Any problem encountered in software engineering can be solved by adding an intermediate layer.

We do not allow all tellers to take and put the ledger, which should be managed by a separate bookkeeper.

In other words, the ledger's access to the ledger is a critical area, and if he only gets one of the ledgers, he will not give it to the teller, but wait for the teller to ask whether both books are there next time.

/ / account administrator public class AccountBookManager {synchronized boolean getAllRequiredAccountBook (Object from, Object to) {if (get all books) {return true;} else {return false }} / / return Resources synchronized void releaseObtainedAccountBook (Object from, Object to) {return the acquired account book}} public class Account {/ / account administrator private AccountBookManager accountBookManager of the singleton Public void transfer (Account target, int amt) {/ / one-time application for transfer from account and transfer to account until successful while (! accountBookManager.getAllRequiredAccountBook (this, target)) {return } try {/ / lock transfer account synchronized (this) {/ / lock transfer account synchronized (target) {if (this.balance > amt) {this.balance-= amt; target.balance + = amt } finally {accountBookManager.releaseObtainedAccountBook (this, target);}

Destroy the inalienable condition

The above has given you a small hint, in order to solve the built-in lock obsession, Java displays lock support notification (notify/notifyall) and wait (wait), that is to say, this function can achieve shouting, old man, iron son's account book for me to use first, after using the function returned to you, this will be explained later when it comes to Java SDK related content.

Break the loop waiting condition

It is also very simple to destroy the waiting condition of the loop. We only need to sort the size of the resource number to solve this problem and remove the loop.

Continue to use code to illustrate:

Class Account {private int id; private int balance; / / transfer void transfer (Account target, int amt) {Account smaller = this Account larger = target; / / sort if (this.id > target.id) {smaller = target; larger = this } / / Lock accounts with small serial numbers synchronized (smaller) {/ / synchronized (larger) {if (this.balance > amt) {this.balance-= amt; target.balance + = amt;}

When smaller is occupied, other threads are blocked and there is no deadlock.

Additional instructions

In actual business, Account will be database objects, which can be solved through transactions or optimistic locks of the database. In addition, in distributed systems, the role of ledger administrator may also be solved by redis distributed locks.

When dealing with breaking requests and holding conditions, we use the while loop to constantly request locks. In the actual business, we will have timeout settings to prevent endless waste of CPU utilization.

In addition, you can try to use Ali open source tool Arthas to view CPU utilization, threading and other related issues. There are clear instructions on github.

Public void transfer (Account target, int amt) {/ / one-time application for transfer out and transfer to account Until while (accountBookManager.getAllRequiredAccountBook (this, target)) {} try {/ / locks out account synchronized (this) {/ / locks transfer account synchronized (target) {if (this.balance > amt) {this.balance-= amt Target.balance + = amt;} finally {accountBookManager.releaseObtainedAccountBook (this, target);}} at this point, the study on "how to avoid java deadlock" is over, hoping to solve everyone's doubts. The collocation of theory and practice can better help you learn, go and try it! If you want to continue to learn more related knowledge, please continue to follow the website, the editor will continue to work hard to bring you more practical articles!

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