Java 新手 求解 死锁要怎么处理 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
coderstory
V2EX    Java

Java 新手 求解 死锁要怎么处理

  •  
  •   coderstory
    coderstory 2021 年 7 月 21 日 3086 次点击
    这是一个创建于 1642 天前的主题,其中的信息可能已经有所发展或是发生改变。

    题是 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()); } } } } 
    9 条回复    2021-07-22 22:09:57 +08:00
    kekxv
        1
    kekxv  
       2021 年 7 月 21 日 via iPhone   1
    先锁支出的,拿走,解锁,再锁接收的
    lakehylia
        2
    lakehylia  
       2021 年 7 月 21 日
    扣完钱就可以解锁转出账户了,然后再尝试锁转入账户加钱。
    zhgg0
        3
    zhgg0  
       2021 年 7 月 21 日   1
    所有线程按同一个顺序加锁。比如你这个情况,可以按照账号 id 的顺序加锁。
    不管是账号 A 转给账号 B,还是账号 B 转给账号 A ;两个线程都是先锁账号 A,再锁账号 B 。
    yogogo
        4
    yogogo  
       2021 年 7 月 22 日
    转账交易,AB 两个账号都应该同时加锁
    lff0305
        5
    lff0305  
       2021 年 7 月 22 日 via Android
    帐号 a,b 排个序,加锁小的,再加锁大的,try 转账,finally 解锁大的,解锁小的 肯定没死锁
    no1xsyzy
        6
    no1xsyzy  
       2021 年 7 月 22 日
    哲学家就餐问题
    wqhui
        7
    wqhui  
       2021 年 7 月 22 日
    两个账号一起锁了
    yuk1no
        8
    yuk1no  
       2021 年 7 月 22 日 via iPhone
    直接 stm
    MoHen9
        9
    MoHen9  
       2021 年 7 月 22 日 via Android
    不管是 A 给 B 转账,还是 B 给 A 转账,逻辑都是一样的。
    扣钱时锁被扣钱的账户,加钱时锁被加钱的账户。

    两个独立账户没必要一起上锁,只要遇到错误可回退就可以,而且各自的账户可以用各自的锁,也不用争同一个锁。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5762 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 34ms UTC 06:53 PVG 14:53 LAX 22:53 JFK 01:53
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86