Java 关于多线程访问和编辑全局字段
我试图使用多线程来模拟单个银行帐户上的两个用户,即取款和存款。我希望两个用户对单个共享变量进行操作,当然,这表示帐户余额 存款或取款操作是随机选择的-1或2(分别存款和取款)。存款时,我希望存款操作需要1秒,取款操作需要0.5秒。在这个时间间隔内,线程必须等待另一个线程完成一个操作,然后才能提取/存放自己 然而,我最大的问题是这两个线程如何分别编辑一个共享的数字字段,即余额。我第一次尝试时,每个线程都创建了自己的平衡实例,并分别对它们执行操作。我希望每个线程的操作(取款/存款)影响全局字段“余额”,而不是实例字段 到目前为止,我已经构建了线程类和驱动程序类,如下所示 线程创建者类:Java 关于多线程访问和编辑全局字段,java,multithreading,runnable,Java,Multithreading,Runnable,我试图使用多线程来模拟单个银行帐户上的两个用户,即取款和存款。我希望两个用户对单个共享变量进行操作,当然,这表示帐户余额 存款或取款操作是随机选择的-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()方法,以便调用同步的存款和取款方法?还是我遗漏了什么?