当账户A对账户B进行转账时,首先需要获取到两把锁:账户A和账户B的锁。获取两把锁成功,且余额大于0,则扣除转出人的余额,并增加收款人的余额,而且这些操作都是在一个原子操作中获取锁的顺序相反导致死锁,即线程1获取到账户A的锁,然后请求账户B的锁,线程2已经获取到账户B的锁,然后请求A的锁,结果两者互相等待对方的锁,造成死锁。
publicclass TransferMoney implements Runnable { Integer flag = 1; static Account a = new Account(1000); static Account b = new Account(1000); // 堆代码 duidaima.com //主函数 public static void main(String[] args) throws InterruptedException { TransferMoney t1 = new TransferMoney(); TransferMoney t2 = new TransferMoney(); t1.flag = 1; t1.flag = 0; Thread thread1 = new Thread(t1); Thread thread2 = new Thread(t2); thread1.start(); thread2.start(); thread1.join(); thread1.join(); System.out.println("a的余额为:"+a.balance); System.out.println("a的余额为:"+b.balance); } @Override public void run() { if (flag == 1) { transferMoney(a, b, 500); } if (flag == 0) { transferMoney(b, a, 500); } } // 转账 private void transferMoney(Account from, Account to, int amount) { synchronized (from) { System.out.println(Thread.currentThread().getName()+"获取到第一把锁"); //加入线程睡眠500ms try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (to) { System.out.println(Thread.currentThread().getName()+"获取到第二把锁"); if (from.balance - amount < 0) { System.out.println("余额不足,转账失败。"); return; } from.balance -= amount; to.balance += amount; System.out.println("成功转账" + i + "元"); } } } staticclass Account { //余额 int balance; public Account(int balance) { this.balance = balance; } } }打印结果:
public class MultiTransferMoney { // 堆代码 duidaima.com private static final int NUM_ACCOUNTS = 5000;//账号数 private static final int NUM_MONEY = 1000;//余额 private static final int NUM_ITERATIONS = 10000000;//转账次数 private static final int NUM_THREADS = 20;//转账人数 public static void main(String[] args) { Random random = new Random(); TransferMoney.Account[] accounts = new TransferMoney.Account[NUM_ACCOUNTS]; //初始化 for (int i = 0; i < accounts.length; i++) { accounts[i] = new TransferMoney.Account(NUM_MONEY); } //转账类 class TransferThread extends Thread{ @Override public void run() { for (int i = 0; i < NUM_ITERATIONS; i++) { //随机下标 int fromAcct = random.nextInt(NUM_ACCOUNTS); int toAcct = random.nextInt(NUM_ACCOUNTS); int amount = random.nextInt(NUM_ACCOUNTS); transferMoney(accounts[fromAcct], accounts[toAcct],amount); } System.out.println("程序结束!!!!"); } private void transferMoney(Account from, Account to, int amount) { synchronized (from) { synchronized (to) { if (from.balance - amount < 0) { System.out.println("余额不足,转账失败。"); return; } from.balance -= amount; to.balance += amount; System.out.println("成功转账" + i + "元"); } } } } //线程数 for (int i = 0; i < NUM_THREADS; i++) { new TransferThread().start(); } } }打印结果:
## 需要首先获取程序的进程 pid jps ## 然后在 终端界面执行如下命令 jstack 8359 #javahome下的jastack命令 进程的pid执行结果图:
/** * 堆代码 duidaima.com * 通过 ThreadMXBean 检测死锁 */ import java.lang.management.ManagementFactory; import java.lang.management.ThreadInfo; import java.lang.management.ThreadMXBean; publicclass ThreadMXBeanDetection implements Runnable{ int flag = 1;//标记位 static Object lock1 = new Object(); static Object lock2 = new Object(); public static void main(String[] args) throws InterruptedException { ThreadMXBeanDetection r1 = new ThreadMXBeanDetection(); ThreadMXBeanDetection r2 = new ThreadMXBeanDetection(); r1.flag=1; r2.flag=0; Thread thread1 = new Thread(r1); Thread thread2 = new Thread(r2); thread1.start(); thread2.start(); Thread.sleep(1000); //得到实例 ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); long[] deadlockedThreads = threadMXBean.findDeadlockedThreads(); //发现死锁 if (deadlockedThreads != null && deadlockedThreads.length>0){ //迭代 for (long item : deadlockedThreads) { //获取线程信息 ThreadInfo threadInfo = threadMXBean.getThreadInfo(item); //获取死锁线程的名字 System.out.println("发现死锁:"+threadInfo.getThreadName()); } } } @Override public void run() { System.out.println("flag= " + flag); if (flag == 1) { synchronized (lock1){ try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (lock2){ System.out.println(flag); } } } if (flag == 0) { synchronized (lock2){ try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (lock1){ System.out.println(flag); } } } } }打印结果:
public class TransferMoney implements Runnable { // 堆代码 duidaima.com private int flag = 1; private static Account a = new Account(500); private static Account b = new Account(500); private static Object lock = new Object(); public static void main(String[] args) throws InterruptedException { TransferMoney r1 = new TransferMoney(); TransferMoney r2 = new TransferMoney(); r1.flag = 1; r2.flag = 0; //定义两个线程,flag = 1和0分别模拟a和b Thread t1 = new Thread(r1); Thread t2 = new Thread(r2); t1.start(); t2.start(); t1.join(); t2.join(); System.out.println("a的余额" + a.balance); System.out.println("b的余额" + b.balance); } @Override public void run() { if (flag == 1) { //a转账给b transferMoney(a, b, 200); } if (flag == 0) { //b转账给a transferMoney(b, a, 200); } } /** * 转账方法 * * @param from 转出人 * @param to 收款人 * @param amount 转账金额 */ public static void transferMoney(Account from, Account to, int amount) { /** * 辅助类 */ class Helper { public void transfer() { if (from.balance - amount < 0) { System.out.println("余额不足,转账失败。"); return; } from.balance -= amount; to.balance = to.balance + amount; System.out.println("成功转账" + amount + "元"); } } //使用类的hash值来帮助排序 int fromHash = System.identityHashCode(from); int toHash = System.identityHashCode(to); // 通过System.identityHashCode(XXX)去获取对象的hash值,并进行比较他们的hash值来进行比较来决定拿锁的顺序 if (fromHash < toHash) { synchronized (from) { System.out.println(Thread.currentThread().getName() + "获取到第一把锁"); synchronized (to) { System.out.println(Thread.currentThread().getName() + "获取到第二把锁"); new Helper().transfer(); } } } else if (fromHash > toHash) { synchronized (to) { System.out.println(Thread.currentThread().getName() + "获取到第一把锁"); synchronized (from) { System.out.println(Thread.currentThread().getName() + "获取到第二把锁"); new Helper().transfer(); } } } else { //发生hash碰撞时,可以增加第三把锁来进行控制,类似“加时赛” synchronized (lock) { synchronized (to) { System.out.println(Thread.currentThread().getName() + "获取到第一把锁"); synchronized (from) { System.out.println(Thread.currentThread().getName() + "获取到第二把锁"); new Helper().transfer(); } } } } } /** * 收款账户 */ static class Account { public Account(int balance) { this.balance = balance; } int balance; } }打印结果: