线程死锁研究
如果服务器当机或应用程序运行得如蜗牛,其中可能原因之一是被称为死锁线程问题。线程死锁就是一直处于堵塞BLOCKED 状态。
什么是死锁?两个线程A和B,那么死锁发生时,线程A块在等待线程B释放监视器锁,而线程B块,因为它也在等待线程A释放相同的监视器锁。
我们可以通过一些工具和技术可以帮助找出堵塞,如jVisualVM的,jstack和UNIX的kill命令。
以转账为案例,A帐号转钱到B账户,下面是账户代码:
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;
}
}
下面是模拟死锁的调用代码:
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);
}
}
}
}
}
这是启动20个线程进行两个账户转账,注意transfer方法使用了synchronized。
假设有两个线程A和B分别同时访问账户1和2,然后就会出现问题,当线程A锁住其1号的fromAccount,并试图锁定账号2的toAccount,。同时线程B锁住2号的fromAccount的,尝试锁定1号帐户的toAccount,。因此,线程A被线程B阻塞的,线程B被线程A阻塞 -陷入 一个僵局。
代码运行输出结果是:
下页
java多线程
Java同步或锁
Java性能调优