分析Java死锁:分析jstack日志(一)

2014-11-24 09:07:04 · 作者: · 浏览: 0
本文中我将展示一段垃圾代码,这段代码会产生死锁,这样围绕这段代码重点展示三种不同的方法来分析线程日志,从而得知什么地方有问题。
下面的讨论将用到两个类 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 accounts = new ArrayList();
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 d