当前位置:编程学习 > JAVA >>

分析Java死锁:分析jstack日志

本文中我将展示一段垃圾代码,这段代码会产生死锁,这样围绕这段代码重点展示三种不同的方法来分析线程日志,从而得知什么地方有问题。
下面的讨论将用到两个类 Account 和 DeadlockDemo classes 定义如下:
 
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;
  }
}
 
The above class models a bank account with attributes of account number and balance, and operations such as deposit(...) and withdraw(...). withdraw(...) will throw a simple checked exception, OverdrawnException, if the amount to withdraw is greater than the available balance.
 
The remaining classes in the example code are DeadlockDemo and its nested class 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;
    }
 
    @Override
    public 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,日志如下:
 
2012-10-16 13:37:03
Full thread dump Java HotSpot(TM) 64-Bit Server VM (20.10-b01-428 mixed mode):
 
"DestroyJavaVM" prio=5 tid=7f9712001000 nid=0x110247000 waiting on condition [00000000]
   java.lang.Thread.State: RUNNABLE
 
"Thread-21" prio=5 tid=7f9712944000 nid=0x118d76000 waiting for monitor entry [118d75000]
   java.lang.Thread.State: BLOCKED (on object monitor)
 at threads.deadlock.DeadlockDemo$BadTransferOperation.transfer(DeadlockDemo.java:86)
 - waiting to lock <7f3366f58> (a threads.deadlock.Account)
 - locked <7f3366ee0> (a threads.deadlock.Account)
 at threads.deadlock.DeadlockDemo$BadTransferOperation.run(DeadlockDemo.java:59)
 
"Thread-20" prio=5 tid=7f971216c000 nid=0x118c73000 waiting for monitor entry [118c72000]
   java.lang.Thread.State: BLOCKED (on object monitor)
 at threads.deadlock.DeadlockDemo$BadTransferOperation.transfer(DeadlockDemo.java:86)
 - waiting to lock <7f3366e98> (a threads.deadlock.Account)
 - locked <7f3366f58> (a threads.deadlock.Account)
 at threads.deadlock.DeadlockDemo$BadTransferOperation.run(DeadlockDemo.java:59)
 
"Thread-19" prio=5 tid=7f9712943800 nid=0x118b70000 waiting for monitor entry [118b6f000]
   java.lang.Thread.State: BLOCKED (on object monitor)
 at threads.deadlock.DeadlockDemo$BadTransferOperation.transfer(DeadlockDemo.java:81)
 - waiting to lock <7f3366f40> (a threads.deadlock.Account)
 at threads.deadlock.DeadlockDemo$BadTransferOperation.run(DeadlockDemo.java:5
补充:软件开发 , Java ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,