闽公网安备 35020302035485号
当账户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;
}
}
打印结果: