打破冷漠僵局文章_研究僵局–第1部分
打破冷漠僵局文章
我敢肯定我們都去過那里:太晚了,您餓了,您的服務器已掛起,或者您的應用程序正在以蝸牛的速度運行,并且有人喘著粗氣想要您解決問題,然后再去解決。 您的應用程序意外掛起的可能原因之一是稱為死鎖的線程問題。 無需贅述,線程可以處于多種狀態之一,如下面的UML狀態圖所示……
…死鎖與BLOCKED狀態有關,API文檔將其定義為“一個等待監視器鎖定而被阻塞的線程”。
那么,什么是僵局? 簡而言之,在給定兩個線程A和B的情況下,當線程A由于等待線程B釋放監視器鎖定而阻塞時,線程B因等待線程A釋放相同的監視器鎖定而阻塞而發生死鎖。
但是,事情可能比這更復雜,因為死鎖可能包含一堆線程。 例如,線程A因為正在等待線程B而阻塞,線程B因為正在等待線程C而阻塞,線程C因為正在等待線程D而阻塞,所以線程D因為正在等待E,E而阻塞,因為它正在等待F和F阻塞,因為它正在等待A。
訣竅是找出哪些線程被阻塞以及為什么被阻塞,這是通過從應用程序中獲取線程轉儲來完成的。 線程轉儲只是快照報告,顯示給定時間點所有應用程序線程的狀態。 有幾種工具和技術可以幫助您掌握線程轉儲,包括jVisualVM , jstack和unix kill命令。 但是,在獲取和解釋線程轉儲之前,我需要一些代碼來創建死鎖
我為此選擇的方案是簡單的銀行帳戶轉帳之一。 這個想法是,有一個余額轉移程序正在運行,該程序使用一堆線程在不同帳戶之間隨機轉移各種金額。 在此程序中,使用以下非常簡單的Account類表示銀行帳戶:
public class Account {private final int number;private int balance;public Account(int number, int openingBalance) {this.number = number;this.balance = openingBalance;}public void withdraw(int amount) throws OverdrawnException {if (amount > balance) {throw new OverdrawnException();}balance -= amount;}public void deposit(int amount) {balance += amount;}public int getNumber() {return number;}public int getBalance() {return balance;} }上面的類為銀行帳戶建模,該銀行帳戶具有帳號和余額屬性,以及諸如deposit(...)和withdraw(...) 。 如果要提取的金額大于可用余額,則withdraw(...)將引發一個簡單的已檢查異常OverdrawnException 。
示例代碼中其余的類是DeadlockDemo及其嵌套類BadTransferOperation 。
public class DeadlockDemo {private static final int NUM_ACCOUNTS = 10;private static final int NUM_THREADS = 20;private static final int NUM_ITERATIONS = 100000;private static final int MAX_COLUMNS = 60;static final Random rnd = new Random();List<Account> accounts = new ArrayList<Account>();public static void main(String args[]) {DeadlockDemo demo = new DeadlockDemo();demo.setUp();demo.run();}void setUp() {for (int i = 0; i < NUM_ACCOUNTS; i++) {Account account = new Account(i, rnd.nextInt(1000));accounts.add(account);}}void run() {for (int i = 0; i < NUM_THREADS; i++) {new BadTransferOperation(i).start();}}class BadTransferOperation extends Thread {int threadNum;BadTransferOperation(int threadNum) {this.threadNum = threadNum;}@Overridepublic void run() {for (int i = 0; i < NUM_ITERATIONS; i++) {Account toAccount = accounts.get(rnd.nextInt(NUM_ACCOUNTS));Account fromAccount = accounts.get(rnd.nextInt(NUM_ACCOUNTS));int amount = rnd.nextInt(1000);if (!toAccount.equals(fromAccount)) {try {transfer(fromAccount, toAccount, amount);System.out.print(".");} catch (OverdrawnException e) {System.out.print("-");}printNewLine(i);}}// This will never get to here...System.out.println("Thread Complete: " + threadNum);}private void printNewLine(int columnNumber) {if (columnNumber % MAX_COLUMNS == 0) {System.out.print("\n");}}/*** The clue to spotting deadlocks is in the nested locking - synchronized keywords. Note that the locks DON'T* have to be next to each other to be nested.*/private void transfer(Account fromAccount, Account toAccount, int transferAmount) throws OverdrawnException {synchronized (fromAccount) {synchronized (toAccount) {fromAccount.withdraw(transferAmount);toAccount.deposit(transferAmount);}}}} }DeadlockDemo提供了創建DeadlockDemo的應用程序框架。 它有兩個簡單的任務: setup()和run() 。 setup()創建10個帳戶,并使用一個帳號和一個隨機的期初余額對其進行初始化。 run()創建嵌套類BadTransferOperation 20個實例,該實例僅擴展Thread并使它們開始運行。 請注意,用于線程數和帳戶數的值完全是任意的。
BadTransferOperation是所有動作發生的地方。 它的run()方法循環循環10000次,從accounts列表中隨機選擇兩個帳戶,并將0到1000之間的隨機數從一個accounts轉移到另一個accounts 。 如果fromAccount中的資金不足,則會引發異常,并在屏幕上顯示“-”。 如果一切順利,并且傳輸成功,則為“。”。 在屏幕上打印。
事情的核心是包含FAULTY同步代碼的方法transfer(Account fromAccount, Account toAccount, int transferAmount) :
synchronized (fromAccount) {synchronized (toAccount) {fromAccount.withdraw(transferAmount);toAccount.deposit(transferAmount);}}此代碼首先鎖定fromAccount ,然后toAccount轉移現金,隨后釋放這兩個鎖定前。
給定兩個線程A和B以及帳戶1和2,那么當線程A鎖定其編號為1的fromAccount并嘗試將其鎖定為帳戶2的toAccount ,將出現問題。同時,線程B鎖定其fromAccount ,編號2和嘗試鎖定其toAccount ,即帳戶號1。因此,線程A在線程B上被toAccount ,線程B在線程A上被阻塞–死鎖。
如果運行此應用程序,則將獲得一些類似于以下內容的輸出:
…隨著程序突然停止。
現在,我有一個死鎖的應用程序,我的下一個博客實際上將掌握線程轉儲,并了解它的全部含義。
參考: Captain Debug's Blog博客中的調查死鎖–第1部分,來自我們的JCG合作伙伴 Roger Hughes。
翻譯自: https://www.javacodegeeks.com/2012/10/investigating-deadlocks-part-1.html
打破冷漠僵局文章
總結
以上是生活随笔為你收集整理的打破冷漠僵局文章_研究僵局–第1部分的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 以下哪项是DDOS攻击的整体特点(以下哪
- 下一篇: 一类医疗器械备案有效期是几年(一类医疗器