I've got a little confused about using atomic/volatile/sync in my code.
Let's say I have an object of book info in a bookstore and for example, it may happen that two threads want to take the same book while the amount in the inventory is only 1, how can I promise that only one thread will take the book?
do I have to use synchronize?
BookInventoryInfo:
package bgu.spl.mics.application.passiveObjects;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Passive data-object representing a information about a certain book in the inventory.
*
* <p>
*
*/
public class BookInventoryInfo {
//The title of the book, his amount in the inventory and the price
private String bookTitle;
private AtomicInteger amountInInventory;
private int price;
public BookInventoryInfo(String bookTitle, int amountInInventory, int price) {
this.bookTitle = bookTitle;
this.price = price;
this.amountInInventory = new AtomicInteger(amountInInventory);
}
/**
* Retrieves the title of this book.
* <p>
* #return The title of this book.
*/
public String getBookTitle() {
return this.bookTitle;
}
/**
* Retrieves the amount of books of this type in the inventory.
* <p>
* #return amount of available books.
*/
public int getAmountInInventory() {
return this.amountInInventory.get();
}
/**
* Retrieves the price for book.
* <p>
* #return the price of the book.
*/
public int getPrice() {
return this.price;
}
public void reduceAmountInInventory() {
this.amountInInventory.decrementAndGet();
}
}
The way I want to take the book:
if(book.getAmountInInventory > 0)
{
book.amountInInventory--
}
You should use synchronized as using AtomicInteger isn't as simple as it might appear at first glance. While individual operations on AtomicInteger are thread safe, using multiple operations might not be. Your example is a good one. say you have
// say it start at 1
Thread1: if(book.getAmountInInventory > 0)
Thread2: if(book.getAmountInInventory > 0)
Thread1: book.amountInInventory--
Thread2: book.amountInInventory--
The amount is now -1.
If you use synchronized it is much simpler to hold the lock for the whole operation
synchronized (book) {
if(book.getAmountInInventory > 0) // no chance for a race condition here.
{
book.amountInInventory--
}
An AtomicInteger isn't sufficient here. While it would allow you to decrement the number of copies in the inventory atomically, that isn't enough - you don't need to just decrement it atomically, you also need to add some custom logic.
I'd use a plain old int, and protect its modification with explicit synchronized blocks or methods:
public class BookInventoryInfo {
private String bookTitle;
private int amountInInventory;
private int price;
public synchronized void checkOut() {
if (amountInInventory <= 0) {
throw new BookCheckoutException("No book in inventory");
}
amountInInventory--;
}
// All the other methods...
}
As an alternative to synchronization, you can also use a compareAndSet:
int a = book.amountInventory.get();
if (a > 0) {
boolean updated = book.amountInInventory.compareAndSet(a, a - 1);
}
This will only decrement the value of amountInInventory if its value is still a when you come to update it. The return value of compareAndSet indicates whether the value was changed or not.
You can wrap this in a loop, something like:
while (true) {
int a = book.amountInventory.get();
if (a == 0) {
return false; // To mean "no book in inventory";
}
if (book.amountInInventory.compareAndSet(a, a - 1)) {
return true; // To mean "there was a book in inventory, and it was removed".
}
}
Related
I have a ParkingLot class with a getEmptySpaces() method that applies to ParkingLot objects, which are arrays of Car objects.
I want to call lot.getEmptySpaces(), but my IDE, Netbeans, throws a fit if I give it an array rather than a specific item. lot[1].getEmptySpaces() compiles fine, but crashes when it runs, as expected, since it's supposed to receive an array, not a null.
How do I call a method on an array defined by the same class?
// Main
ParkingLot[] lot = new ParkingLot[10];
lot[1].getEmptySpaces(); // compiles but doesn't run
lot.getEmptySpaces(); // what i want to run but doesn't
// Car class
public class Car {
private String color;
private String licensePlate; // lp #
public Car(String color, String licensePlate) {
this.color = color;
this.licensePlate = licensePlate;
}
/**
* #return the color
*/
public String getColor() {
return color;
}
/**
* #param color the color to set
*/
public void setColor(String color) {
this.color = color;
}
/**
* #return the licensePlate
*/
public String getLicensePlate() {
return licensePlate;
}
/**
* #param licensePlate the licensePlate to set
*/
public void setLicensePlate(String licensePlate) {
this.licensePlate = licensePlate;
}
#Override
public String toString() {
return "Car{" + "color=" + color + ", licensePlate=" + licensePlate + '}';
}
}
// ParkingLot class
public class ParkingLot {
private Car[] spaces; // lp=000000 color=none will represent an empty space
private int currentIndex;
/**
* Creates a parkingLot object
*
* #param size how many spaces are needed in the parking lot
*/
public ParkingLot(int size) {
// Array Example: String[] arr = new String[20];
this.spaces = new Car[size];
this.currentIndex = 0;
}
public int getEmptySpaces(){
int emptySpaces = 0;
for(int i = 0; i < spaces.length; i++){
if (spaces[i] == null){
emptySpaces++;
}
}
return emptySpaces;
}
/**
* Adds a car to the parking lot
*
* #param car the car to be added to the parking lot
*/
public void addCar(Car car){
spaces[currentIndex] = car;
currentIndex++;
}
}
ParkingLot[] lot = new ParkingLot[10];
It feels like you imagine this creates a single parking lot with 10 spaces.
It doesn't.
It creates a plot of land upon which up to 10 parking lots can be placed, though none are there yet (a ParkingLot is an object, if you want one to exist, somebody, somewhere, must invoke new ParkingLot(), or no parking lot objects exist).
lot[1].getEmptySpaces()
This goes to the second lot (java is 0-indexed, so, lot[1] is the second lot), and asks it: Oi, how much free space is there? Given that you're yelling this at an empty space where a parking lot can be, but isn't, you get a NullPointerException.
lot.getEmptySpaces();
This makes no sense at all. How can you ask 10 parking lots at once? Even worse, how can you ask a bit of terrain reserved for 10 parking lots, but where no lots exist right now?
Relevant:
for (int i = 0; i <lots.size; i++) lots[i] = new ParkingLot();
The problem I was having was that I created an array of ParkingLot objects. I only needed one ParkingLot, not 10.
My code should have been:
ParkingLot lot = new ParkingLot[10];
Instead of:
ParkingLot[] lot = new ParkingLot[10];
It was just a typo, like usual.
I have a list of Player Objects that contain details such as below
Player{FirstName='Marco', LastName='Reus', Team='Dortmund', Country='Germany', Fitness='Unfit', RecoveryTime='Slow'}
This program is essentially designed to take the players fitness and recovery time into account and return a set of action plans to help them get fit.
I've utilised enums and given each enum an integer value aValue.
public enum LevelOfFitness {
/**
* Enum that represent the different level of Fitness of each player
*/
CAREER_IN_DOUBT(8), INDEFINITELY_INJURED(7), INJURED(6), UNFIT(5), CLOSE_TO_FITNESS(4),
NEAR_MATCH_FIT(3),
MATCH_FIT(2), DATA_DEFICIENT(1), NOT_EVALUATED(0);
private int value;
LevelOfFitness (int aValue) {
this.value = aValue;
}
public int getValue () {
return value;
}
}
I have also got a set of enum action plans:
public enum ActionPlans{
GRADUAL_REHABILITATION, SURGERY, INTENSE_GYM_AND_THERAPY, NO_ACTION_NEEDED,REST_AND_REHABILITATION
}
I'm trying to for example for Marco in the example, if the player is 5 in LevelofFitness which is unfit and recovery time is slow, return Gradual rehabilitation as a action plan.
Many thanks
I think you need an extra method LevelOfFitness.from(String) and another getActionPlan for given player.
public LevelOfFitness from(String value){
// do some input checks
LevelOfFitness found = null;
for(LevelOfFitness level : LevelOfFitness.values()){
if(level.name().equalsIgnoreCase(value)){
return level;
}
}
throw new IllegalStateException("Not able to find fitness level for " + value);
}
public ActionPlans getActionPlan(Player player){
String fitness = player.getFitness();
LevelOfFitness levelOfFitness = LevelOfFitness.from(fitness);
ActionPlans actionPlan = null;
if(fitnessLevelOfFitness.getValue() == 5){
actionPlan = GRADUAL_REHABILITATION;
}
.....
return actionPlan;
}
You could even put such method inside Player class itself, in this case you could encapsulate further the logic without passing the player reference.
I'm attempting to create a method called "runExperiments()
the first step in the loop is to decrement a variable called "powerLevel" by a random number between 1 and 3 which is I have created a second method for which works.
the next step which is where I am having problem is if the "powerLevel" can be reduced then I need a message containing the experiment number (starting at 1) should displayed, if not then a different message should be displayed and the remaining experiments should not be attempted.
Then finally when all expierements have finished I need to display "Experiment run stopped" But I know how to do this section.
I have posted all the code below. The method is at the bottom. I have made a first attempt but I cannot seem to figure out the part in the bold. Any help or guidance would be fantastic. I'm not sure if I have used the correct type of loop either so that may be wrong as well.
public class SpaceRocket
{
private String name;
private int maxPowerLevel;
private int numberOfExperiments;
private int powerLevel;
private int decreasePowerLevel;
/**
* returns maxPowerLevel
*/
public int getMaxPowerLevel()
{
return this.maxPowerLevel;
}
/**
* returns numberOfExperiments
*/
public int getNumberofExperiments()
{
return this.numberOfExperiments;
}
/**
* returns powerLevel
*/
public int getPowerLevel()
{
return this.powerLevel;
}
/**
*
* Causes execution to pause by time number of milliseconds
*
*/
public void delay(int time)
{
try
{
Thread.sleep(time);
}
catch (Exception e)
{
System.out.println(e);
}
}
/**
*
* return a random integer between 1 and 3 inclusive
*/
public int randomInteger()
{
java.util.Random r = new java.util.Random();
return r.nextInt(3) + 1;
}
public SpaceRocket(String aName, int aNumberOfExperiments)
{
this.name = aName;
this.numberOfExperiments = aNumberOfExperiments;
this.powerLevel = 0;
this.maxPowerLevel = 15;
}
public boolean decrementPower(int adecreasePowerLevel)
{
this.decreasePowerLevel = adecreasePowerLevel;
if(decreasePowerLevel > this.powerLevel)
{
this.powerLevel = 0;
return true;
}
else
{
this.powerLevel =(this.powerLevel - this.decreasePowerLevel);
return false;
}
}
public runExperiments()
{
for(this.powerLevel =(this.powerLevel - randomIntegar())
{
if(this.powerLevel
}
}
If I understand your question correctly, every time the loop runs, you want to decrease "powerlevel" by a random value, then display a message depending on whether powerlevel can be reduced.
Here are two approaches.
1) use an if statement in your for loop
for (conditions){
if(powerlevel cannot be decremented){
//display a messsage
break;
}
// display a message
}
conditions could be iterating through all the experiments
2) use a while loop which checks whether powerlevel can be reduced in every loop
while(powerlevel can be decreased){
//display a message containing the experiment number (starting at 1)
}
//display a different message
I am sending prices to customers (10000+) but below code has loop that causes delays in the process for customers waiting for calculations.
PriceVisibleForCustomer = Price + CustomerMargin
Price - changing every 300ms - sent from central store, not related to customer instance
CustomerMargn - some plus or minus amount that is resulting from customer agreement/segment/administrator decision etc. It doesnt change during customer http session, I can keep it in memory
Customer - he takes part in the process after he logs in, he should see rapidly changing prices of 8 products.
Maybe I need some more technology ? I have Spring 3/4, Java, Weblogic and i could create even separate webapp for this task for providing calculated prices.
I thought about threads in Java but 10000+ customers would mean too many threads wouldnt it ? How to change this code? Maybe I should change architecture but how?
/**
* Sends prices to customer. This method is called very often (300ms) as prices are changing in real time.
* Customer should see prices also each 300ms
* #param productId - id of a product that prices will be calculated
* #param productIdToPriceMap
* #param customerIdToMarginMap - this map is changed every time customer logs in or logs out
*/
private static void sendPricesToCustomers(Long productId,
Map<Long, BigDecimal> productIdToPriceMap,
Map<Long, BigDecimal> customerIdToMarginMap) {
//This loop is blocking last customer from receiving price until all other customers wil have theri prices calculated. I could create threads, 10000+ customers will be logged in, I cant create so much threads... can I?
for (Long customerId: customerIdToMarginMap.keySet()){
BigDecimal customerMargin = customerIdToMarginMap.get(customerId);
BigDecimal priceResult = productIdToPriceMap.get(productId).add(customerMargin);
//send priceResult to websocket
}
}
Here is a simple example of the Listener pattern, I am not sure if this approach will work for you but just throwing out some ideas ...
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Vector;
import javax.swing.Timer;
public class Demo {
public static Product[] PRODUCTS = new Product[]{
new Product("Computer", 400),
new Product("Desk", 800),
new Product("Chair", 70),
new Product("Printer", 300),
new Product("Television", 200)
};
public static void main(String[] args) throws InterruptedException {
Customer john = new Customer("John", 3);
john.addProduct(PRODUCTS[1]);
john.addProduct(PRODUCTS[2]);
john.addProduct(PRODUCTS[3]);
Customer mary = new Customer("Mary", 2);
mary.addProduct(PRODUCTS[1]);
mary.addProduct(PRODUCTS[2]);
mary.addProduct(PRODUCTS[4]);
Thread.sleep(10000);
System.exit(0);
}
}
interface IPriceListener {
public void priceChanged(Product product, int price);
}
class Customer implements IPriceListener {
String _name;
int _margin;
Vector<Product> _products = new Vector<Product>();
public Customer(String name, int margin){
_name = name;
_margin = margin;
}
public void addProduct(Product product){
_products.add(product);
product.addListener(this);
}
public void priceChanged(Product product, int price) {
System.out.println("[" + _name + "][" + _products.get(_products.indexOf(product)).getName() + "][" + price + "][" + (price + _margin) + "]");
}
}
class Product implements ActionListener {
private int _startingPrice;
private int _currentPrice;
private String _name;
private Timer _timer;
private Vector<IPriceListener> _listeners = new Vector<IPriceListener>();
public Product(String name, int price) {
_name = name;
_startingPrice = _currentPrice = price;
_timer = new Timer(300, this);
_timer.start();
}
public void addListener(IPriceListener listener) {
_listeners.add(listener);
}
public void removeListener(IPriceListener listener){
_listeners.remove(listener);
}
private void notifyListeners() {
for(IPriceListener listener : _listeners){
listener.priceChanged(this, getCurrentPrice());
}
}
public void actionPerformed(ActionEvent e) {
_currentPrice = _startingPrice + (int)(Math.random() * (5 - (-5))) + (-5);
notifyListeners();
}
public final String getName() {
return _name;
}
private synchronized final int getCurrentPrice() {
return _currentPrice;
}
}
One way to handle this is to create a single thread whose job is to consume priceResults off a queue and send them down the websocket (I'm assuming you have only one websocket). Your loop would then push priceResults onto the queue every 300ms without blocking the websocket thread. See ConcurrentLinkedQueue javadoc.
Edit:
To avoid the delay between finishing the current loop through customerIdToMarginMap and beginning to loop through the next update, here are some options:
Keep the queue concept and create a fixed thread pool where each thread pulls the next customerId/productIdToPriceMap/customerIdToMarginMapoff the queue. If you have four threads and 10,000 records, each thread will only have to process 2,500 records, thereby starting on the next 300ms data push 4 times earlier than your current implementation. Increase thread count as you find necessary for performance.
Keep my original queue concept but change the way you receive the price updates. The reason you need to loop is because you're getting pricing updates for every customer at the same time. If you can instead e.g. create a threaded listener for a group of customers that receives a customerIdToMarginMap containing only customerIds it's meant to handle, the iteration time will be significantly decreased.
I am an absolute programming beginner, and I am trying to learn Java from a book. I'm very confused.
The book has an exercise (this is like halfway through the chapter, so there's a lot building up to this, but I'll try to make it clear) that asks us to add a method to a class. Basically, we were given a prebuilt set of classes that are supposed to be like a simple auction program. So there is an array list which contains a list of bidders, how much they bid, and the lot number. This exercise asks us to add a method that will print out a list of the names of the winning bidders and the value of their bids.
Okay, that makes sense. I can wrap my mind around how it is supposed to work. I even wrote the following code: `
/**
* Exercise 4.48
* for each item in the list of lots, get the highest bid.
* if highest bid is not null, print the bidder and value
* otherwise, print "lot not sold"
*/
public void close()
{
for(Lot lot : lots) {
Bid highestBid = lot.getHighestBid();
if(highestBid != null) {
System.out.println(bidder, value);
}
else{
System.out.println("Lot not sold.");
}
}
}
When try to compile it, it stops on bidder because I haven't defined the variable. So obviously I am supposed to tell it what "bidder" is supposed to mean. Bidder is the name of the variable in the "Person" object in the same program and is used throughout the project, but I'm still not clear on how to get it to understand that my "bidder" is the same "bidder." I assume that I will have the same issue with "value."
What am I missing?
Edited to make the code actually look like code.
As requested, here is the Person... class? (I'm not great with the terminology. I'll get there. Sorry.)
/**
* Maintain details of someone who participates in an auction.
* #author David J. Barnes and Michael Kölling.
* #version 2011.07.31
*/
public class Person
{
// The name of this person.
private final String name;
/**
* Create a new person with the given name.
* #param name The person's name.
*/
public Person(String name)
{
this.name = name;
}
/**
* #return The person's name.
*/
public String getName()
{
return name;
}
}
**/**
* A class to model an item (or set of items) in an
* auction: a lot.
*
* #author David J. Barnes and Michael Kölling.
* #version 2011.07.31
*/
public class Lot
{
// A unique identifying number.
private final int number;
// A description of the lot.
private String description;
// The current highest bid for this lot.
private Bid highestBid;
/**
* Construct a Lot, setting its number and description.
* #param number The lot number.
* #param description A description of this lot.
*/
public Lot(int number, String description)
{
this.number = number;
this.description = description;
this.highestBid = null;
}
/**
* Attempt to bid for this lot. A successful bid
* must have a value higher than any existing bid.
* #param bid A new bid.
* #return true if successful, false otherwise
*/
public boolean bidFor(Bid bid)
{
if(highestBid == null) {
// There is no previous bid.
highestBid = bid;
return true;
}
else if(bid.getValue() > highestBid.getValue()) {
// The bid is better than the previous one.
highestBid = bid;
return true;
}
else {
// The bid is not better.
return false;
}
}
/**
* #return A string representation of this lot's details.
*/
public String toString()
{
String details = number + ": " + description;
if(highestBid != null) {
details += " Bid: " +
highestBid.getValue();
}
else {
details += " (No bid)";
}
return details;
}
/**
* #return The lot's number.
*/
public int getNumber()
{
return number;
}
/**
* #return The lot's description.
*/
public String getDescription()
{
return description;
}
/**
* #return The highest bid for this lot.
* This could be null if there is
* no current bid.
*/
public Bid getHighestBid()
{
return highestBid;
}
}
**
/**
* A class that models an auction bid.
* It contains a reference to the Person bidding and the amount bid.
*
* #author David J. Barnes and Michael Kölling.
* #version 2011.07.31
*/
public class Bid
{
// The person making the bid.
private final Person bidder;
// The value of the bid. This could be a large number so
// the long type has been used.
private final long value;
/**
* Create a bid.
* #param bidder Who is bidding for the lot.
* #param value The value of the bid.
*/
public Bid(Person bidder, long value)
{
this.bidder = bidder;
this.value = value;
}
/**
* #return The bidder.
*/
public Person getBidder()
{
return bidder;
}
/**
* #return The value of the bid.
*/
public long getValue()
{
return value;
}
}
import java.util.ArrayList;
/**
* A simple model of an auction.
* The auction maintains a list of lots of arbitrary length.
*
* #author David J. Barnes and Michael Kölling.
* #version 2011.07.31
*
* 3/12/15 added close method exercise 4.48
*
*/
public class Auction
{
// The list of Lots in this auction.
private ArrayList<Lot> lots;
// The number that will be given to the next lot entered
// into this auction.
private int nextLotNumber;
/**
* Create a new auction.
*/
public Auction()
{
lots = new ArrayList<Lot>();
nextLotNumber = 1;
}
/**
* Enter a new lot into the auction.
* #param description A description of the lot.
*/
public void enterLot(String description)
{
lots.add(new Lot(nextLotNumber, description));
nextLotNumber++;
}
/**
* Show the full list of lots in this auction.
*/
public void showLots()
{
for(Lot lot : lots) {
System.out.println(lot.toString());
}
}
/**
* Make a bid for a lot.
* A message is printed indicating whether the bid is
* successful or not.
*
* #param lotNumber The lot being bid for.
* #param bidder The person bidding for the lot.
* #param value The value of the bid.
*/
public void makeABid(int lotNumber, Person bidder, long value)
{
Lot selectedLot = getLot(lotNumber);
if(selectedLot != null) {
Bid bid = new Bid(bidder, value);
boolean successful = selectedLot.bidFor(bid);
if(successful) {
System.out.println("The bid for lot number " +
lotNumber + " was successful.");
}
else {
// Report which bid is higher.
Bid highestBid = selectedLot.getHighestBid();
System.out.println("Lot number: " + lotNumber +
" already has a bid of: " +
highestBid.getValue());
}
}
}
/**
* Return the lot with the given number. Return null
* if a lot with this number does not exist.
* #param lotNumber The number of the lot to return.
*/
public Lot getLot(int lotNumber)
{
if((lotNumber >= 1) && (lotNumber < nextLotNumber)) {
// The number seems to be reasonable.
Lot selectedLot = lots.get(lotNumber - 1);
// Include a confidence check to be sure we have the
// right lot.
if(selectedLot.getNumber() != lotNumber) {
System.out.println("Internal error: Lot number " +
selectedLot.getNumber() +
" was returned instead of " +
lotNumber);
// Don't return an invalid lot.
selectedLot = null;
}
return selectedLot;
}
else {
System.out.println("Lot number: " + lotNumber +
" does not exist.");
return null;
}
}
/**
* Exercise 4.48
* for each item in the list of lots, get the highest bid.
* if highest bid is not null, print the bidder and value
* otherwise, print "lot not sold"
*/
public void close()
{
for(Lot lot : lots) {
Bid highestBid = lot.getHighestBid();
if(highestBid != null) {
System.out.println(bidder, value);
}
else{
System.out.println("Lot not sold.");
}
}
}
Thanks for clarifying your question by providing the supporting code!
This should fix your problem. Change this line:
System.out.println(bidder, value);
to this:
System.out.println(highestBid.getBidder().getName() + " bids " + highestBid.getValue())
The highestBid variable stores an object of type Bid. You can see the Bid class definition to see what it means for an object to have type Bid. Basically, a Bid object has a method called getValue(), which returns the value of the bid, and a method getBidder(), which returns a Person object (an object that abides by the Person class definition). So, look in the Person class and see how a Person object has a method called getName(), which returns the name of the person as a String.
Finally, we can just print the name and value with our handy built-in System.out.println() function.
To teach you the very basic,
Consider a class as a real life object,
It has it own characteristics which you define as class variables.
These should be (generally) defined private so a call to them has to happen from a class-function (getters and setters). The reason why we do this is so you can setup some restrictions. (like: "not higher than 3" or "must be min. 4 char. long" ...)
The class functions are like: small hidden classes within a Class they execute some code. Notice the "In", functions IN class. not the other way around. So the variables you create inside the functions are not known to the class, but the function knows the class-variables.
I would suspect in your case that you called to bidderand value:
Without use of getters if they are defined private outside the same class where your close() function is defined.
But really it is very hard for us to know what is wrong. Please provide us with the classof the close() function
EDIT:
the code for close()should be...
public void close()
{
for(Lot lot : lots) {
Bid highestBid = lot.getHighestBid();
if(highestBid != null) {
System.out.println(highestBid.getBidder(), highestBid.getValue());
}
else{
System.out.println("Lot not sold.");
}
}