heap memory usage anomaly?
I've been running this program overnight hoping to see it crash and burn (because the book said so), and while it hasn't shown any signs of deadlock, I've noted that the heap memory usage has tripled from ~20Mb to ~60Mb.
Screenshot here.
Any ideas?
Code:
package homenetwork.bkr.training;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.management.ManagementFactory;
/**
* This program shows data corruption when multiple threads access a data structure.
* @author Administrator
*/
public class UnsynchBankTest {
public static void main (String[] args)
{
if (debug)
getPID();
Bank b = new Bank(NACCOUNTS, INITIAL_BALANCE);
int i;
for (i = 0; i < NACCOUNTS; i++)
{
TransferRunnable r = new TransferRunnable(b, i, INITIAL_BALANCE);
Thread t = new Thread(r);
t.start();
}
}
public static void getPID() {
try {
System.out.println("1. Take note of the PID and hit ENTER");
System.out.println("2. Run jconsole + PID (e.g. jconsole 4288");
System.out.println("PID = " + ManagementFactory.getRuntimeMXBean().getName());
//TODO if (debug) Automatically run jconsole + <pid>
//open up standard input
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String s = br.readLine();
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
}
public static final int NACCOUNTS = 10;
public static final double INITIAL_BALANCE = 2000;
private static boolean debug = true;
}
package homenetwork.bkr.training;
/**
* A runnable that transfers money from an account to other accounts in a bank.
* @author Administrator
*/
public class TransferRunnable implements Runnable {
/**
* Constructs a transfer runnable.
* @param b: the bank between whose account money is transferred.
* @param from: the account to transfer money from.
* @param max: the maximum amount of money in each transfer
*/
public TransferRunnable(Bank b, int from, double max)
{
bank = b;
fromAccount = from;
maxAmount = max;
}
public void run()
{
try
{
while (true)
{
int toAccount = (int) (bank.size() * Math.random());
double amount = maxAmount * Math.random();
bank.transfer(fromAccount, toAccount, amount);
Thread.sleep((long) ((int) DELAY * Math.random()));
}
}
catch (InterruptedException e) {}
}
private Bank bank;
private int fromAccount;
private double maxAmount;
private int DELAY = 10;
}
package homenetwork.bkr.training;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
/**
* A bank with a number of bank accounts.
*/
public class Bank {
/** Constructs the bank.
* @param n: the number of accounts
* @param initialBalance: the initial balance for each account
*/
public Bank (int n, double initialBalance)
{
accounts = new double[n];
for (int i = 0; i < accounts.length; i++)
accounts[i] = initialBalance;
bankLock = new ReentrantLock();
sufficientFunds = bankLock.newCondition();
}
/**
* Transfers money from one account to another.
* @param from: the account to transfer from
* @param to: the account to transfer to
* @param amount: the amount to transfer
* @throws InterruptedException
*/
public void transfer (int from, int to, double amount) throws InterruptedException
{
bankLock.lock(); //ensure that only one thread can be run at a time
try {
while (accounts[from] < amount)
sufficientFunds.await();
System.out.print(Thread.currentThread());
accounts[from] -= amount;
System.out.printf("%10.2f from %d to %d", amount, from, to);
accounts[to] += amount;
System.out.printf(" Total balance: %10.2f%n", getTotalBalance());
/* unblock all other threads in the wait set for this condition
i.e. "We have sufficient funds and processed this thread, any other thread needs this account?".
*/
sufficientFunds.signalAll();
}
finally
{
bankLock.unlock();
}
}
/**
* Gets the sum of all account balances.
* @return: the total balance
*/
public double getTotalBalance()
{
bankLock.lock();
try {
double sum = 0;
for (double a: accounts)
sum += a;
return sum;
}
finally {
bankLock.unlock();
}
}
/**
* Gets the number of accounts in the bank.
* @return: the number of accounts
*/
public int size()
{
return accounts.length;
}
private final double[] accounts;
private final ReentrantLock bankLock;
private Condition sufficientFunds;
}