Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/383.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 关于多线程访问和编辑全局字段_Java_Multithreading_Runnable - Fatal编程技术网

Java 关于多线程访问和编辑全局字段

Java 关于多线程访问和编辑全局字段,java,multithreading,runnable,Java,Multithreading,Runnable,我试图使用多线程来模拟单个银行帐户上的两个用户,即取款和存款。我希望两个用户对单个共享变量进行操作,当然,这表示帐户余额 存款或取款操作是随机选择的-1或2(分别存款和取款)。存款时,我希望存款操作需要1秒,取款操作需要0.5秒。在这个时间间隔内,线程必须等待另一个线程完成一个操作,然后才能提取/存放自己 然而,我最大的问题是这两个线程如何分别编辑一个共享的数字字段,即余额。我第一次尝试时,每个线程都创建了自己的平衡实例,并分别对它们执行操作。我希望每个线程的操作(取款/存款)影响全局字段“余额

我试图使用多线程来模拟单个银行帐户上的两个用户,即取款和存款。我希望两个用户对单个共享变量进行操作,当然,这表示帐户余额

存款或取款操作是随机选择的-1或2(分别存款和取款)。存款时,我希望存款操作需要1秒,取款操作需要0.5秒。在这个时间间隔内,线程必须等待另一个线程完成一个操作,然后才能提取/存放自己

然而,我最大的问题是这两个线程如何分别编辑一个共享的数字字段,即余额。我第一次尝试时,每个线程都创建了自己的平衡实例,并分别对它们执行操作。我希望每个线程的操作(取款/存款)影响全局字段“余额”,而不是实例字段

到目前为止,我已经构建了线程类和驱动程序类,如下所示

线程创建者类:

public class BankAccountSim extends Thread{
public double balance = 1000;
public String threadName;

BankAccountSim(String name){
    threadName = name;
}
public void run(){
    System.out.println(threadName + "account initiated.");
    while(true){
        try{
            Random rand = new Random();
            int num = rand.nextInt(2) + 1;
            if(num == 1){
                System.out.println(threadName + " is depositing in the bank.");
                balance += 1;
                System.out.println("The new balance is " + balance + " dollars" );
                Thread.sleep(1000);
                Thread.yield();
            }
            else{
                System.out.println(threadName + " is withdrawing from the bank.");
                balance -= 1;
                System.out.println("The new balance is " + balance + " dollars.");
                Thread.sleep(500);
                Thread.yield();
                }
        }

        catch(InterruptedException e){
            System.out.println("Process terminated.");
            }
        }
    }
}
线程驱动程序类:

import java.util.concurrent.ThreadLocalRandom;
import java.util.Random;

public class BankAccountSimDriver {
    public static void main(String[] args){

    Thread user1 = new BankAccountSim("user1");
    Thread user2 = new BankAccountSim("user2");

    user1.start();
    user2.start();

    }
}

这主要是一个设计问题。你最好创建一个银行账户并与客户分享,就像在现实世界中一样

interface BankAccount {
    // Query the balance
    BigDecimal balance();

    // Make a deposit and return the new balance
    BigDecimal deposit(BigDecimal amount);

    // Make a withdrawal and return the new balance
    BigDecimal withdraw(BigDecimal amount);
}

// Implements the Runnable interface for run in another thread.
class BankClient implements Runnable {
    private final String clientName;

    private final BankAccount bankAccount;

    public BankClient(String clientName, BankAccount bankAccount) {
        this.clientName = clientName;
        this.bankAccount = bankAccount;
    }

    public void run() {
        // while(true) ...
    }
}

class SimpleBankAccount implements BankAccount {
    private BigDecimal balance = BigDecimal.ZERO;

    public SimpleBankAccount(BigDecimal initialBalance) {
        this.balance = initialBalance;
    }

    public synchronized BigDecimal balance () {
        return balance;
    }

    public synchronized BigDecimal deposit(BigDecimal amount) {
        return balance = balance.add(amount);
    }

    public synchronized BigDecimal withdraw(BigDecimal amount) {
        if (balance.compareTo(amount) < 0) {
            throw new RuntimeException("Not enough balance.");
        }
        return balance = balance.subtract(amount);
    }
}

public class SimDriver {
    public static void main(String[] args) throws Exception {
        BankAccount account = new SimpleBankAccount(BigDecimal.valueOf(1000));

        Thread t1 = new Thread(new BankClient("client-1", account));
        thread t2 = new Thread(new BankClient("client-2", account));

        t1.start();
        t2.start();

        t1.join();
        t2.join();
    }
}
接口银行账户{
//查询余额
大十进制余额();
//存入存款并退还新的余额
大额十进位存款(大额十进位金额);
//提取并归还新的余额
BigDecimal提款(BigDecimal金额);
}
//实现在另一个线程中运行的可运行接口。
类BankClient实现Runnable{
私有最终字符串clientName;
私人最终银行账户;
public BankClient(字符串clientName,BankAccount BankAccount){
this.clientName=clientName;
this.bankAccount=银行账户;
}
公开募捐{
//虽然(真的)。。。
}
}
类SimpleBankAccount实现BankAccount{
私有BigDecimal余额=BigDecimal.0;
公共SimpleBankAccount(BigDecimal初始余额){
this.balance=初始平衡;
}
公共同步双十进制余额(){
收益余额;
}
公共同步BigDecimal存款(BigDecimal金额){
返回余额=余额。添加(金额);
}
公共同步BigDecimal取款(BigDecimal金额){
if(余额比较(金额)<0){
抛出新的RuntimeException(“余额不足”);
}
返回余额=余额减去(金额);
}
}
公共类SimDriver{
公共静态void main(字符串[]args)引发异常{
银行账户=新的SimpleBankAccount(BigDecimal.valueOf(1000));
线程t1=新线程(新银行客户机(“客户1”,账户));
线程t2=新线程(新的银行客户机(“客户2”,账户));
t1.start();
t2.start();
t1.join();
t2.连接();
}
}

有趣的是,您希望在它自己的线程中有一个,但不要将
银行帐户
视为一个线程,该操作是一个线程。关于这个设计的一个注意事项。我个人的经验法则是,我只对基本类型使用
volatile
。如果将
balance
更改为
Double
或其他对象,请锁定
对象
或使用和
原子引用
或其他对象

public class BankAccount {
    static volatile double balance = 0;

    public void deposit(double amount) {
        class Deposit implements Runnable {
            double amount;
            Deposit(double d) { amount = d; }
            public void run() {
                balance += amount;
            }
        }
        new Thread(new Deposit(amount)).run();
    }
    public synchronized void withdraw(double amount) {
        class Withdraw implements Runnable {
            double amount;
            public Withdraw(double d) { amount = d; }
            public void run() {
                balance -= amount;
            }
        }
        new Thread(new Withdraw(amount)).run();
    }

    //
    // A little Test 
    //
    public static void main(String[] args) {
        BankAccount ba = new BankAccount();

        ba.deposit(34576.2);
    }
}

一个简单的解决方案是通过改变以下内容来实现平衡:

public double balance = 1000;

public AtomicInteger balance = new AtomicInteger(1000);
但是,您需要稍微修改更新余额的方式,例如添加:

balance.addAndGet(1);

您可以将
余额
设置为静态,甚至可以使用原子整数,而不是将
BankAccountSim
线程
扩展,只需将其设置为一个简单的类。创建该类的单个实例,然后将其传递给线程,然后线程将对其执行操作
BankAccountSim
应提供
synchronized
方法,用于
向账户提取
存款
,如果您确实想使用此代码,那么,金钱永远不应该是一个
双重
我认为这个确切的场景已经在核心Java第1卷中讨论过了。Hi Luke-非常有用,但有一个问题:如何在BankAccount类中编写run()方法,以便调用同步的存款和取款方法?还是我遗漏了什么?