Hello all,
I'm emulating an extremely simplified stock exchange. I've got three classes; HitStock, Broker and EngageBroker (sort of a test class). HitStock must be a singleton holding stocks brokers want to buy. I should be able to use multiple Broker classes running concurrently, buying and selling the stocks from HitStock. I should print every transaction to the output. Also, HitStock stocks cannot go below 0 but can go above their initial value.
I'm not entirely satisfied with my solution. I'm looking for some improvements. Any advice will be appreciated.
/**
* This singleton class holds HitStock stocks.
*/
public final class HitStock {
private static final HitStock INSTANCE = new HitStock();
private int availableStocks = 1000;
/**
* Instantiation disabled.
*/
private HitStock() {
}
/**
* Returns the instance of this class.
*
* @return HitStock instance of this class.
*/
public static HitStock getInstance() {
return INSTANCE;
}
/**
* Sells stocks of this class to the requesting broker.
*
* @param amount
* Integer amount of stocks to sell.
* @return Returns true if the transaction is performed, false otherwise.
*/
public synchronized boolean replyToBuyRequest(final int amount) {
if (amount < 1 || amount > availableStocks) {
return false;
}
availableStocks -= amount;
return true;
}
/**
* Buys stocks of this class from the requesting broker.
*
* @param amount
* Integer amount of stocks to buy.
* @return Returns true if the transaction is performed, false otherwise.
*/
public synchronized boolean replyToSellRequest(final int amount) {
if (amount < 1) {
return false;
}
availableStocks += amount;
return true;
}
/**
* Returns available stocks of this class.
*
* @return Returns available stocks of this class.
*/
public synchronized int getAvailableStocks() {
return availableStocks;
}
/**
* Returns a String representation of this class.
*
* @return Returns a String representation of this class.
*/
public synchronized String toString() {
return String.format("HitStock stocks available: %d", availableStocks);
}
}
/**
* Class representing a stock broker, trading with HitStock stocks.
*/
public class Broker {
private final HitStock stocks;
private final int brokerID;
private static int allBrokers;
private int currentStocks;
/**
* Constructs a new Broker with HitStock stocks available for trading.
*
* @param stocksOwned
* Number of available HitStock stocks.
*/
public Broker(final int stocksOwned) {
stocks = HitStock.getInstance();
currentStocks = stocksOwned;
brokerID = ++allBrokers;
}
/**
* Tries to buy stocks from HitStock.
*
* @param amount
* Number of stocks trying to buy.
* @return Returns true if the transaction is performed, false otherwise.
*/
public boolean requestBuy(final int amount) {
if (amount < 1 || !stocks.replyToBuyRequest(amount)) {
return false;
}
currentStocks += amount;
return true;
}
/**
* Tries to sell stocks to HitStock.
*
* @param amount
* Number of stocks trying to sell.
* @return Returns true if the transaction is performed, false otherwise.
*/
public boolean requestSell(final int amount) {
if (amount < 1 || amount > currentStocks
|| !stocks.replyToSellRequest(amount)) {
return false;
}
currentStocks -= amount;
return true;
}
/**
* Returns available stocks of this class.
*
* @return Returns available stocks of this class.
*/
public int getCurrentStocks() {
return currentStocks;
}
/**
* Returns the number ID of this class.
*
* @return Returns the number ID of this class.
*/
public int getBrokerId() {
return brokerID;
}
/**
* Prints the available stocks from this class and HitStock class to the
* standard output.
*/
public void printBrokerInfo() {
System.out.println(this);
System.out.format("HitStock stocks available: %d%n", stocks
.getAvailableStocks());
}
/**
* Returns a String representation of this class.
*
* @return Returns a String representation of this class.
*/
public String toString() {
return String.format("Broker %d : %d stocks available.", brokerID,
currentStocks);
}
}
import java.util.Random;
/**
* This class emulates a trading broker.
*/
public class EngageBroker implements Runnable {
private static final Random RAND = new Random();
private Broker broker;
/**
* Constructs a new EngageBroker.
*/
public EngageBroker() {
broker = new Broker(RAND.nextInt(250));
}
/**
* Tries to buy stocks from HitStock.
*/
private void buy() {
broker.printBrokerInfo();
final int amount = RAND.nextInt(500) + 1;
final boolean success = broker.requestBuy(amount);
if (success) {
System.out.format("Bought %d stocks.%n", amount);
} else {
System.out.format("Failed to buy %d stocks.%n", amount);
}
broker.printBrokerInfo();
System.out.println("********************");
}
/**
* Tries to sell stocks from HitStock.
*/
private void sell() {
broker.printBrokerInfo();
final int amount = RAND.nextInt(500) + 1;
final boolean success = broker.requestSell(amount);
if (success) {
System.out.format("Sold %d stocks.%n", amount);
} else {
System.out.format("Failed to sell %d stocks.%n", amount);
}
broker.printBrokerInfo();
System.out.println("********************");
}
/**
* Sleeps for a random amount of time.
*
* @throw InterruptedException if the thread is interrupted.
*/
private void sleep() {
try {
Thread.sleep(RAND.nextInt(2000));
} catch (InterruptedException e) {
}
}
/**
* Emulation of the trading broker.
*/
public void run() {
for (int i = 0; i < 5; i++) {
sleep();
buy();
sleep();
sell();
}
}
public static void main(String[] args) {
new Thread(new EngageBroker()).start();
new Thread(new EngageBroker()).start();
new Thread(new EngageBroker()).start();
new Thread(new EngageBroker()).start();
new Thread(new EngageBroker()).start();
}
}