4

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

 2 years ago
source link: https://www.v2ex.com/t/790916
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

V2EX  ›  Java

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

  coderstory · 3 小时 52 分钟前 · 359 次点击

题目是 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());
            }
        }
    }
}



About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK