【问题标题】:Using the correct way to Synchronized to avoid data loss使用正确的同步方式避免数据丢失
【发布时间】:2020-06-30 20:15:08
【问题描述】:

我正在尝试创建一个多线程的 ATM 系统,以避免提款请求的数据丢失。

我创建了 2 个线程,每个线程都试图从银行余额中提取 1000-5000 钱。

我不希望线程一起工作,我希望每个线程都等待第二个线程完成工作。 当余额为0或提现请求高于当前余额时,两个线程都应该停止提款。

我的问题是,我看到 Thread1 运行了 4 次,让 Thread2 进入,以此类推 Thread2,似乎他们没有等待对方进入动作。

主要:

class Main {
    public static void main(String args[]) {
        Bank bank = new Bank(100000);
        ThreadSync threadSync = new ThreadSync();
        Thread client1 = new ClientThread(bank, threadSync,1);
        Thread client2 = new ClientThread(bank, threadSync,2);


        client1.start();
        client2.start();
    }
}

银行:

public class Bank {
    private int balance;
    public Bank(int balance) {
        this.balance = balance;
    }
    public int getBalance() {
        return balance;
    }

    public void setBalance(int balance) {
        this.balance = balance;
    }
}

客户端线程:

public class ClientThread extends Thread {
    private Bank bank;
    private ThreadSync threadSync;
    private int client;

    ClientThread(Bank bank, ThreadSync threadSync, int client) {
        this.bank = bank;
        this.threadSync = threadSync;
        this.client = client;
    }

    @Override
    public void run() {

        int randomNumber;
        while (bank.getBalance() > 0) {
            synchronized (threadSync) {
                randomNumber = ((int) (Math.random() * (5000 - 1000 + 1)) + 1000);
                try {
                    if (bank.getBalance() - randomNumber >= 0) {
                        bank.setBalance(bank.getBalance() - randomNumber);
                    }
                    System.out.println(client + " - " + bank.getBalance() + " withdrawed - " + randomNumber);
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

线程同步:

public class ThreadSync {
    public void send(String msg)
    {
        System.out.println("Sending\t"  + msg );
        try
        {
            Thread.sleep(1000);
        }
        catch (Exception e)
        {
            System.out.println("Thread  interrupted.");
        }
        System.out.println("\n" + msg + "Sent");
    }
}

谢谢!

【问题讨论】:

  • 我不希望线程一起工作,我希望他们每个人都等待第二个线程完成工作。线程用于支持并发处理(做事线程之间是通用的,但以不干涉的方式)。在我看来,您最好按顺序执行此操作。而且你没有解释你遇到的问题。
  • @WJS,我已经更新了问题,你说的顺序是什么意思?
  • 一个接一个。或者一个接一个地完成另一个任务而不是同时(同时或几乎同时但不相互干扰)。例如,许多不同的客户应该能够同时取出和存款(并发处理) 而不是在其他人开始之前必须等待对方完成交易(顺序处理)。
  • 如果我让线程完成他的任务,线程2就没有钱了
  • 每个线程尝试取出资金时应处理资金不足。在某些情况下,这可能是先到先得的情况。

标签: java multithreading synchronization


【解决方案1】:

不是一个完整的答案,但你应该知道这是一个错误的模式:

while (...trivial test...) {
    synchronized(lock) {
        ...something that takes some time...
    }
}

问题是每次循环释放锁时,它所做的几乎下一件事就是再次重新锁定它。如果线程 A 进入循环,然后线程 B 随后尝试进入,那么线程 B 很可能是 starved。

当线程 B 尝试进入同步块时,它会被操作系统swapped out(也称为“阻塞”、“进入睡眠”)。

当线程 A 释放锁时,操作系统需要一段时间才能将线程 B 重新换回。同时,线程 A 已经处于领先地位:它重新锁定锁,重新开始工作,当线程 B 准备好运行时,已经太晚了。操作系统将再次换出 B,下一次迭代可能会发生同样的事情,下一次,...


诀窍是重新构建您的程序,以便线程永远不需要将锁保持锁定很长时间。这听起来可能有些矛盾,但有时您可以通过让线程执行额外工作来加速并行计算,前提是这些额外的工作能够让它们相互避开。

如果您无法重新构建程序以使大部分实际工作发生在关键部分(即“锁定”部分)之外,那么这可能表明您正在尝试解决问题solve 不太适合多线程解决方案。

【讨论】:

    猜你喜欢
    • 2014-07-12
    • 1970-01-01
    • 2021-03-22
    • 1970-01-01
    • 1970-01-01
    • 2020-09-23
    • 2021-08-27
    • 2022-06-13
    • 1970-01-01
    相关资源
    最近更新 更多