题目是 10 个线程 对应 20 个账号 每个线程执行 100 次 任意 2 个账号之间的金额交易
代码实现中遇到了死锁
假设线程 A 对 账户 A 账户 B 执行交易 ( A 转钱到 B ) 线程 B 对账户 B 和账户 A 执行交易( B 转钱到 A )
我代码写的是先锁一个账号 判断账号余额是否足够,然后锁另一个账户 最后执行转账
但是同时有 2 个线程执行了 2 个相同账户的反向操作时,就会死锁了。
package cn.bobmao.logic.service;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
public class Test {
class Account {
int index;
int balance = 100;
public Account(int index) {
this.index = index;
}
}
public static void main(String[] args) throws InterruptedException {
new Test().run();
}
public void run() throws InterruptedException {
AtomicInteger sum = new AtomicInteger(0);
List<Account> accounts = new ArrayList<>();
for (int i = 0; i < 20; i++) {
accounts.add(new Account(i));
}
ExecutorService executorService = Executors.newFixedThreadPool(10);
CountDownLatch latch = new CountDownLatch(1000);
for (int i = 0; i < 10; i++) {
executorService.submit(new Pay(accounts, latch, sum));
}
latch.await();
int count = 0;
for (Account account : accounts) {
count += account.balance;
}
System.out.println(count);
}
class Pay implements Runnable {
List<Account> accounts;
CountDownLatch latch;
AtomicInteger sum;
public Pay(List<Account> accounts, CountDownLatch latch, AtomicInteger sum) {
this.accounts = accounts;
this.latch = latch;
this.sum = sum;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
int money = new Random().nextInt(100);
// a->b
int a = new Random().nextInt(20);
int b = new Random().nextInt(20);
latch.countDown();
if (a == b) {
System.out.println("当前执行次数" + sum.getAndIncrement());
continue;
}
Account ac = accounts.get(a);
synchronized (ac) {
System.out.println("锁 ac " + ac.index + " " + Thread.currentThread().getName());
if (ac.balance >= money) {
Account bc = accounts.get(b);
synchronized (bc) {
System.out.println("锁 bc " + ac.index + " " + Thread.currentThread().getName());
ac.balance = ac.balance - money;
bc.balance = bc.balance + money;
//latch.countDown();
}
System.out.println("解锁 bc " + ac.index + " " + Thread.currentThread().getName());
}
}
System.out.println("解锁 ac " + ac.index + " " + Thread.currentThread().getName());
System.out.println("当前执行次数" + sum.getAndIncrement());
}
}
}
}
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.