2012-09-19 137 views
2

我想在使用多线程的Java中创建一个程序。该计划是关于使用借记卡的夫妻之间分享的银行账户。Java多线程程序:多线程中的对象共享

我写了使用2个线程Java程序,但我得到java.lang.NullPointerException

我试图积累我用Java多线程的知识。 帮助我识别此代码块中的错误。

下面是程序:

import java.util.concurrent.locks.Condition; 
import java.util.concurrent.locks.Lock; 
import java.util.concurrent.locks.ReentrantLock; 
import java.util.logging.Level; 
import java.util.logging.Logger; 


// A bank account has a balance that can be changed by deposits and withdrawals. 

public class BankAccount { 

    public double total = 0, amount = 0; 

    public void withdraw(double amount) { 
     total -= amount; 
     System.out.println("Amount Withdrawn is " + amount); 
    } 

    public void deposit(double amount) { 
     total += amount; 
     System.out.println("Amount Deposited is " + amount); 
    } 

    public double getAccount() { 
     System.out.println("Total Amount is " + total); 
     return total; 

    } 
} 

class WithdrawalRunnable { 

    private static final Lock lock = new ReentrantLock(); 
    final Condition myCond = lock.newCondition(); 
    BankAccount myAccount; 

    public void amountWithdrawn(double money_Withdrawn) throws InterruptedException { 
     lock.lock(); 
     try { 
      while (money_Withdrawn > myAccount.total) { 
       myCond.await(); 
       //when the condition is satisfied then : 
       myAccount.withdraw(money_Withdrawn); 
       myAccount.getAccount(); 
      } 
     } finally { 
      lock.unlock(); 
     } 
    } 
} 

class DepositRunnable { 

    private static final Lock lock = new ReentrantLock(); 
    final Condition myCond = lock.newCondition(); 
    BankAccount myAccount; 

    public void amountDeposited(double money_deposited) throws InterruptedException { 
     lock.lock(); 
     try { 
      myAccount.deposit(money_deposited); 
      myAccount.getAccount(); 
      myCond.signalAll(); 
     } finally { 
      lock.unlock(); 
     } 
    } 
} 

class Husband implements Runnable { 

    DepositRunnable myDeposit; 
    WithdrawalRunnable myWithdrawal; 
    double amount_deposit; 
    double amount_withdraw; 

    public Husband(double amount_deposit, double amount_withdraw) { 
     this.amount_deposit = amount_deposit; 
     this.amount_withdraw = amount_withdraw; 
    } 

    public void run() { 
     try { 
      myDeposit.amountDeposited(amount_deposit); 
      myWithdrawal.amountWithdrawn(amount_withdraw); 
     } catch (InterruptedException ex) { 
      Logger.getLogger(Wife.class.getName()).log(Level.SEVERE, null, ex); 
     } 
    } 
} 

class Wife implements Runnable { 

    DepositRunnable myDeposit; 
    WithdrawalRunnable myWithdrawal; 
    double amount_deposit; 
    double amount_withdraw; 

    public Wife(double amount_deposit, double amount_withdraw) { 
     this.amount_deposit = amount_deposit; 
     this.amount_withdraw = amount_withdraw; 
    } 

    public void run() { 
     try { 
      myDeposit.amountDeposited(amount_deposit); 
      myWithdrawal.amountWithdrawn(amount_withdraw); 
     } catch (InterruptedException ex) { 
      Logger.getLogger(Wife.class.getName()).log(Level.SEVERE, null, ex); 
     } 

    } 
} 

class RunningThreadTest { 

    public static void main(String[] args) throws InterruptedException { 

     Husband husb = new Husband(100.0, 0.0); 
     Wife wif = new Wife(400.0, 0.0); 
     Thread thread1 = new Thread(husb); 
     Thread thread2 = new Thread(wif); 
     thread1.start(); 
     thread2.start(); 
    } 
} 
+2

什么生产线是NPE? –

+0

异常在线程 “螺纹-1” 显示java.lang.NullPointerException \t在javaapplication3.todelete.Wife.run(BankAccount.java:116) \t在java.lang.Thread.run(Thread.java:662) 异常在线程“Thread-0”java.lang.NullPointerException \t at javaapplication3.todelete.Husband.run(BankAccount.java:94) \t at java.lang.Thread.run(Thread.java:662) – user1207965

回答

2

这是一个很好的多线程学习案例,我稍微改了一下你的代码。 请将BankAccountManager类与您的两个班级进行比较,我希望这会有所帮助。

import java.util.concurrent.locks.Condition; 
import java.util.concurrent.locks.Lock; 
import java.util.concurrent.locks.ReentrantLock; 
import java.util.logging.Level; 
import java.util.logging.Logger; 

// A bank account has a balance that can be changed by deposits and withdrawals. 

class BankAccount { 

    private double total = 0; 

    public void withdraw(double amount) { 
     total -= amount; 
    } 

    public void deposit(double amount) { 
     total += amount; 
    } 

    public double getAccount() { 
     return total; 

    } 
} 

class BankAccountManager { 

    private static final Lock lock = new ReentrantLock(); 
    private Condition myCond = lock.newCondition(); 
    BankAccount myAccount; 

    public BankAccountManager(BankAccount myAccount) { 
     this.myAccount = myAccount; 
    } 

    public void amountWithdrawn(double money_Withdrawn) 
      throws InterruptedException { 
     lock.lock(); 
     try { 
      if (money_Withdrawn > myAccount.getAccount()) { 
       myCond.await(); 
      } 
      // when the condition is satisfied then : 
      System.out.println("Amount Withdrawn is " + money_Withdrawn); 
      myAccount.withdraw(money_Withdrawn); 
      System.out.println("Total Amount is " + myAccount.getAccount()); 
     } finally { 
      lock.unlock(); 
     } 
    } 

    public void amountDeposited(double money_deposited) 
      throws InterruptedException { 
     lock.lock(); 
     try { 
      System.out.println("Amount Deposited is " + money_deposited); 
      myAccount.deposit(money_deposited); 
      System.out.println("Total Amount is " + myAccount.getAccount()); 
      myCond.signalAll(); 
     } finally { 
      lock.unlock(); 
     } 
    } 
} 

class Husband implements Runnable { 

    private BankAccountManager manager; 
    private double amount_deposit; 
    private double amount_withdraw; 

    public Husband(BankAccountManager manager, double amount_deposit, 
      double amount_withdraw) { 
     this.manager = manager; 
     this.amount_deposit = amount_deposit; 
     this.amount_withdraw = amount_withdraw; 
    } 

    public void run() { 
     try { 
      manager.amountDeposited(amount_deposit); 
      manager.amountWithdrawn(amount_withdraw); 
     } catch (InterruptedException ex) { 
      Logger.getLogger(Wife.class.getName()).log(Level.SEVERE, null, ex); 
     } 
    } 
} 

class Wife implements Runnable { 

    private BankAccountManager manager; 
    private double amount_deposit; 
    private double amount_withdraw; 

    public Wife(BankAccountManager manager, double amount_deposit, 
      double amount_withdraw) { 
     this.manager = manager; 
     this.amount_deposit = amount_deposit; 
     this.amount_withdraw = amount_withdraw; 
    } 

    public void run() { 
     try { 
      manager.amountDeposited(amount_deposit); 
      manager.amountWithdrawn(amount_withdraw); 
     } catch (InterruptedException ex) { 
      Logger.getLogger(Wife.class.getName()).log(Level.SEVERE, null, ex); 
     } 

    } 
} 

public class RunningThreadTest { 

    public static void main(String[] args) throws InterruptedException { 

     BankAccountManager manager = new BankAccountManager(new BankAccount()); 

     Husband husb = new Husband(manager, 100.0, 0.0); 
     Wife wif = new Wife(manager, 400.0, 1.0); 
     Thread thread1 = new Thread(husb); 
     Thread thread2 = new Thread(wif); 
     thread1.start(); 
     thread2.start(); 
    } 
} 
+0

嗨莞松,感谢您的解决方案。您的解决方案比我的工作更好。我在退出时有不正确的答案,但仍然没有弄清楚。也许我认为我并不是假设将相同的变量“金额”用作数据字段,对于存款和撤回,但仍然不确定。是的,你的解决方案没有任何问题,我已经尝试过并且有时间进行逆向工程! :) – user1207965

1

在这两个DepositRunnableWithdrawalRunnable,你永远不会初始化成员myAccount,但你试图在各自的方法来使用它们。尝试在使用它们之前初始化这些成员。

可能会有更多的例子,但这些是我会看到的第一个例子。

+0

Nope,Initializing在两个类中的myAccount没有解决问题,我得到:线程“线程1”中的异常java.lang.NullPointerException \t at javaapplication3.todelete.Wife.run(BankAccount.java:116) \t at java。 lang.Thre广告。运行(Thread.java:662) 异常在线程 “线程0” 显示java.lang.NullPointerException \t在javaapplication3.todelete.Husband.run(BankAccount.java:94) \t在java.lang.Thread.run( Thread.java:662) – user1207965

1

两个通存通兑的Runnable场我的帐户不被初始化

1

我所看到的是,出现在类DepositRunnable和WithdrawalRunnable属性

BankAccount myAccount; 

没有被正确初始化,因此你会在这里得到一个空指针异常:

myAccount.withdraw(money_Withdrawn); 
1

你的许多类成员变量都不是初始化。你的具体问题是因为Wife.myDeposit从未初始化,但一旦你过去了,就会有另一个NPE等着你。

0

是谢谢你,所有这些类需要被初始化如下:

DepositRunnable myDeposit = new DepositRunnable(); 
WithdrawalRunnable myWithdrawal = new WithdrawalRunnable(); 
BankAccount myAccount = new BankAccount(); 

而其他错误,没有人抓,它是:“总”必须是静态的。

谢谢大家。